Photo Organizer

  • Status Assigned
  • Percent Complete
  • Task Type Feature Request
  • Category Backend / Core
  • Assigned To
  • Operating System All
  • Severity Low
  • Priority Very Low
  • Reported Version Devel
  • Due in Version 2.36
  • Due Date Undecided
  • Votes
  • Private
Attached to Project: Photo Organizer
Opened by pizza - 2006-04-25
Last edited by pizza - 2008-01-06

FS#8 - Better permission hierarchy

Right now there are three permissions -- public, private, and "protected", which equates to "public only to all of my clients"

This is pretty lousy; I can certianly envision scenarios where you'd want a client to only see stuff that's specific to that client. To do this now, you have to create separate accounts and mark clients for those specific accounts.

I'd like to see a more generic hierarchical user/group model. Only the photo owner can make changes to their images, but the permission model would break down as follows:

Permissions would be granted on a per-group basis, and individual users can be members of various groups. "Guest" access would just be another group, and would default to assigned.

A permission is inherited; so if "guest" is granted access to the top-level folder, they would be allowed to see everything below it unless a more restrictive permission was specified. This is sort of similar to unix permissions with the "sticky bit" turned on.

This gets a little tricky when talking about folders vs albums, as a user may not be allowed to browse the folder, but the image could be included in a public album. When viewing the image from the folder perspective, it would be disallowed, but from the album perspective, it would be allowed.

EDIT: see

pizza commented on 2006-05-11 14:37

We also need read/write permissions. Multiple people may be given access to update/edit keywords, for example.

Project Manager
Luud commented on 2006-11-01 16:32

I described something like this before on Balint's pages (or maybe in an email to him, can't remember for sure).

The option I would like is to have two (or more) user accounts that share a single set of photos. It does not matter who uploads them, as both will have all owner rights.

Then again, I might want to share not all my photos with all my friends in my group. So I may have multiple groups for different friends. So photos I would like to share with friends in multiple groups. We could solve this by allowing photos to belong to multiple groups or to create groups of groups.

A group could have read, modify and ownership permissions. So a user belonging to a certain group can be treated as owner for a photo that has the ownership flag opened up on its group flag for this group.

Next we can have permission masks. So we could mask out permission on photos when we watch them trough an album, and have a different mask when reached trough a folder.

This may need more thinking. We might be able to create a bit more simplicity in the permissions structure while still retaining the flexibility we seek above.

pizza commented on 2006-11-02 13:50

I think it's as simple as possible, given the functional requirements. Fortunately, the implementation can happen in multiple phases -- the first pass would just implement enough to keep existing functionality functional, second would be the full set of read permissions, and the third would be the full set of write permissions.

pizza commented on 2006-11-02 13:53

This is the schema I came up with a little while ago, plus a psuedocode lookup function.

create sequence groups_sequence start 1;

create table groups (
identifier integer not null primary key,
description text

create table group_memberships (
group integer not null references groups(identifier),
user integer not null references users(identifier)

create table folder_permissions (
folder integer not null references folder(identifier),
group integer not null references groups(identifier),
view boolean not null,
read boolean not null,
edit boolean not null,
delete boolean nut null

create table album_permissions (
album integer not null references album(identifier),
group integer not null references groups(identifier),
view boolean not null,
read boolean not null,
edit boolean not null,
delete boolean nut null

create table photo_permissions (
photo integer not null references photo(identifier),
group integer not null references groups(identifier),
view boolean not null, -- aka preview, basic info
read boolean not null, -- aka "original"
edit boolean not null, -- modify
delete boolean nut null -- remove
-- permissions are looked up as follows:
-- best = none;
-- foreach groups_for_user(userid) {
--- if (lookup (photo,group)) store best2;
--- if (best_2 > best) best = best_2; continue;
-- }
-- if (best) return (best);
-- foreach groups_for_user(userid) {
--- folder = folder_for_photo(photo);
--- if (lookup (folder,group)) store best_2;
--- if (best_2 > best) best = best_2;
--- foreach albums_for_photo(photo) {
--- if (lookup(album, group)) store best_2;
--- if (best_2 > best) best = best_2;
--- }
-- }

My plan is to implement this permission function in pl/pgsql, so we can do something like "select * from photo where read_permission(identifier) is true;' Otherwise it would require an insane set of JOINs or many, many database round trips.

pizza commented on 2006-11-02 14:10

To recreate the current permission model, we need to:

* Create one group per user with only that user in the group. (eg "Solomon" --> "Solomon's Group")
* Create one group per user with all of that user's clients in the group. (eg "Solomon" --> "Solomon's Clients")
* For each image, insert a row into photo_permissions for the appropriate group plus rights (owner, access_type, original_image), and an additional row for the client group if clients have access to the image.
* For each folder, insert a row into folder_permissions with the appropriate settings (owner group, access_type)
* For each album, insert a row into folder_permissions with the appropriate settings (owner group, access_type)

Now, from here things get more complicated. Currently, images, folders, and albums are "owned" by a single user. I'd like to change this so that they're owned by a particular group instead -- basically eliminating the "users" field from both table altogether, replacing it with the appropriate group (containing only that one user). Come to think of it, this would be a natural first phase of the project; the auto-creation of groups and the transformation of the "users" field to "owner" in the photo, album, and folder tables.

Project Manager
Luud commented on 2006-11-02 22:48

I would suggest to keep the owner next to the group field.

To give an example: two persons are adding photos, for some reason, the actions of on eof the two need ot be reversed (e.g. remove those photos). It is the very nice to know who uploaded the photos in the first place.

Fot the rest your proposed steps seem ok to me.

pizza commented on 2006-11-03 21:30

I really don't see this as a problem; perhaps what would be more useful is a proper logfile?

The entire permission model will revolve around groups; this should be extended to photo/album ownership too. When you upload an image, it'll be owned by your "personal" group by default -- with the option of assigning its ownership to any group that the user is a member of. You could, of course, assign read/edit/etc rights to other groups and keep it owned by your personal group.

Project Manager
Luud commented on 2006-11-08 09:04

I just came across what seems to me a bit odd in PO, at least it is not intuitive to me.

I would like to share thumbnails and previews to the public, but not the original.

If I select "Protected" as access rights, then the general public will not even see the thumbnail. So to allow for that I need to set the access rights to "Public".

However, if I do that, then the public can also download the original. As I understood from the remarks in task "  FS#79  — ability to make the original photo available to the public" (, the "High Resolution Original" is "Only accessible for authorized users" doesn't make much sense if the public is authorized. In the current setup, I cannot do what I described above.

It would make more sense to have the following options for "High Resolution Original":
- Owner
- Owner and Users
- Owner, Users and Clients
- Public

Or possibly toggle each of these separately, but that would fit more in the bigger permission change as described in the previous comments of this task.

Maybe  FS#79  should be reopened to change the list as given in this post?

pizza commented on 2006-11-08 15:20

I nearly all of my photos set to "public" and "original only authorized users", and the public can see the image, but not download the original. The "public" is never considered to be authorized; only clients can be potentially authorized.

Yeah, I know it's stupid. And yeah, it needs to be fixed.

But not for 2.33 (As of yesterday I closed the last blocker), and the new permission model is the main feature I have planned for 2.34.

Project Manager
Luud commented on 2006-11-08 16:43

I think you are a bit mistaken, at least if I visit your po demo site.

I have my folder public, the photos in it public and original set to authorized users only. With this setup, anonymous viewers can download the original, just as what is claimed in  FS#79 .

If I look at your demo site, then for example I see you have set the photo permission of the balloon to original downloadable by _owner_ only. This seems to be the difference.

However, I want my fellow users to be able to download the originals, but not anonymous viewers.

This is not a pressing issue at the moment, so I can live with a fix not going into 2.33. (And if I couldn't I should still shut up, as you've been very helpful ;-)

pizza commented on 2006-11-08 20:00

Ah, you are indeed correct; the code does not match the descriptive text. Can you open a new bug ticket for this?

As this bug has probably been present since the beginning, I agree that it can wait for the new permission model, which will bring along its own pile of bugs. :)

I like this permission model. An advanced permission model has been the main feature for which I have been hoping for a couple of years now.

The only addition either now or later that I could see would be to include the option to define which fields could be edited by a particular group. For example, I upload many photos that I take. I would like to allow other users to have the ability to update the caption and the keywords without being able to update the location, date, etc. This could be accomplished with "permission sets". A new table with two columns, field name, and a boolean. Then a foreign key into, most likely, the photo, album and folder permission tables. This field might be able to replace the current boolean "edit" field. This way, if the field is NOT NULL then the users can edit the fields that are in the permission set. There are, of course, lots of othert options that could be used particularly since using a NULL "value" really shouldn't be used to signify anything other than "Unknown".

As well, I completely agree with using pl/pgsql to provide the functionality.

pizza commented on 2006-11-15 14:34

As was pointed out in #116, GROUP is a reserved keyword, so the schema needs updating. See for current plans.

Meanwhile, this notion "permission sets" is interesting, but it's also a complexity that I would prefer to defer. I'm still trying to come up with a permission UI that isn't horribly confusing to users...

pizza commented on 2007-02-13 21:05

The recently-added "password-protected folder" feature conflicts with the proposed permission model.

A solution is to create "password-protected groups". If a user supplies the appropriate password, they're added to that group for that transaction, and can see any protected folders/images.

Registered users could be permenantly/temporarily added to that group, but guest users would need to maintain those credentials in the PHP session, so I guess there's no point in implementing the former just yet.

I'm about to start coding up the migration functions and PL/pgsql lookup code.

pizza commented on 2007-06-24 13:35

I figured out a way to keep the current password model, but I don't know if I'll keep it going forward, but that's TBD.

Meanwhile, I've been converting image/folder/album permission lookups to a stored prodecude model; this way to migrate to the new system all we'll need to do is replace the can_access_*() functions and voila. It doesn't handle 'read/write/edit/etc' permissions yet; I may fix up the function call convention to use this.

pizza commented on 2007-07-08 15:36

with #217, the current model has shifted a little bit. Now, datebook events are the focal point of "protected" access. The folder is associated with an event, and the event is associated with a client user. Either it's that specified user, or they supply the folder password. This eliminates the single greatest weakness of the current model, namely that "all clients can access all protected photos" and it does it in a logical, intuitive manner.

I need to think about how this change will affect the new permission model proposal, but to my thinking:

(1) Add the notion of user groups, and the ability to manage said groups. (2.35)
(2) Migrate the notion of "user ownership" to "group ownership" to all resources in the database, keeping the current set of permissions. (2.35) This would give us 90% of the remaining desired functionality with little additional complexity.

(3) Split the permissions into separate tables, so that fine-grained access control is possible. (aka the proposed "model") (2.36, if ever) The problem with this is that it's very difficult to manage, and higher-level features (ie clients, shoots, etc) have to automagically set/clear permissions as needed. This is a very complex task.

Would it be worthwhile to use an existing ACL library, maybe like Tackle: ?
(I found it just now and have no idea of this specific ACL would be a good pick, it's just an example).

The downside would be that it's php and therefore does not benefit from the performance gains that a stored procedures model would give, but potential upsides would be less coding (probably) and a verified secure model. Maybe there are ready-made solutions for stored procedures as well? I don't know, it just seems like a rather obvious wheel re-invention...

pizza commented on 2008-02-18 16:15

Tackle's design looks pretty similar to what I want to do, but the level of integration I have in mind means we'd need to practically rewrite it anyway.

Meanwhile, the real holdup is (as always) the UI work necessary for a complex ACL system to be truly useful. I have mostly-complete mappings to and from the old system (allowing the old UI to be retained) but any of the more advanced features will require additional work. (Actually I haven't updated the model to more easily deal with clients..)

I've come full-circle several times now, and once again I'm thinking it's best to more incrementally upgrade the current permission model. The most crucial aspect is to denormalize the permissions into their own set of tables. Oddly enough, it's also the least invasive from a code perspective. Initially the UI will remain the same; restricting us to the same functionality we have now.

Once that's done, we can remap the old permissions into the new set (ie view/edit/etc) and make the necessary UI changes to expose that.

Once that's done, we can add group support and UI to manage groups.

Once that's done, we enable "multiple permissions" per item, finally exposing the full permission model to the user.

If one were to tinker with the UI a bit, what format would you like it to be? A "dumb" prototype in CSS/HTML, a use-case flowchart or something else?
(This question also applies to #327)

pizza commented on 2008-02-20 16:07

I've always prototyped UIs on graph paper, at least at the high level. The flowchart is the most important part here.

Here are the components as I see it:

0) Group editor (create/delete/edit groups -- group edit involves adding/deleting users from a group)
1) Basic permission 'row' editor -- eg "Photo X+Group Y" -> 'Read/Display/!Edit/!Original'
2) Aggregate permission editor -- applies a set of permission 'rows' to a given resource. -- Eg 'Photo X' -> GroupY RD!E!O, GroupZ RE!DO

It can be implemented in javascript; I think that'll be simpler overall.

The photo upload page will have a form field that displays the current permission set. When clicked on, it'll pop up the 'aggregate' editor, which will list the permission rows and allow the user to add/edit/delete them through the row editor, another popup. The final permission set is submitted as a single form input, probably in JSON or something like that...

pizza commented on 2008-09-18 03:58

I think I'm going to shoot for this now:


* Create groups sequence and tables. [installer]
* Create group-mangling UI. Admin can do anything!


* Create/fill-in groups: [per-user-private, per-user-allclients, per-user-per-client] based on user/client/calendar tables. [installer]
* Update all "client" references to use group mechanisms instead.
* Migrate Calendar/Events code to use groups instead of userids.
* Alter user creation/deletion code to mangle these per-user groups as needed. [decisions on orphanning?]


* Migrate photos to group ownership. [uid->per-user_private_grp] [installer]
* Migrate folders to group ownership [uid->per_user_private_grp] [installer]
* Migrate albums to group ownership [uid->per_user_private_grp] [installer]
* Migrate folder/album "passwords" to password-protected groups.
* Allow [photo|folder|album] ownership to be changed to any group the user is in.


* Migrate profile/equipment to group ownership

STAGE X: [TBD, may or may not happen]

* Replace PO_USER_TYPE with a set of groups: [admin, all_full_users, all_lite_users, guests] [A user is in exactly one of these!]
* Split out permissions; Read/Edit/Delete/etc
* Push permissions onto a per-file basis rather than per-photo or per-version?


Available keyboard shortcuts


Task Details

Task Editing