-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement group backend #1
Conversation
also:
|
class CustomGroupsManager implements \OCP\GroupInterface { | ||
|
||
const GROUP_ID_PREFIX = 'customgroup_'; | ||
const GROUP_ID_PREFIX_LEN = 12; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's a good idea to hardcode this. The extra cost of calculating the string's length should be meaningless, and we would only maintain one constant.
// FIXME: search by display name instead | ||
if ($search !== '') { | ||
$parameters[] = '%' . $search . '%'; | ||
$searchLike = ' WHERE LOWER(`displayname`) LIKE LOWER(?)'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want lowercase comparations?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For display names I'd say yes
* @return bool | ||
*/ | ||
public function inGroup($uid, $gid) { | ||
$numericGroupId = $this->extractNumericGroupId($gid); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this a bit complex? Why do we want to use prefix?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The prefix is to avoid collisions with groups created in other backends like LDAP, etc.
Also we're using a numeric group id in this backend internally to be able to rename the display name.
Another alternative would be to generate a random hash string id instead of numeric... not sure what's best, I thought this approach would be the simplest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's the backend responsability to resolve the collisions nor to prevent them. Any other backend could have a group with the same name "customgroup_12", and there shouldn't be any reason to avoid it.
I think it's core the one who should take care of how to resolve the collisions. Generally, just saying "I want this group" is enough to know what is the group you're refering to, but maybe sometimes you should say "I want this group which is located in this backend" so there is no doubt about the group you want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While I agree that it's not this backend's responsibility, we'll still get into trouble if all our groups are called "1", "2", "3", etc... And I don't intend to fix core to have its own collision detection / namespacing as part of this task, which is likely a bigger task on its own which might not be backward compatible.
|
Just a couple of extra things:
|
@jvillafanez yes sorry, there is only one group manager. What this PR implements is a group backend like LDAP does. (I mixed up both names...) |
|
Anyway, my first goal with this PR was to experiment to find out whether sharing would work automatically with this approach. It did! |
If you test this you'll see that the display name is correctly shown in the sharee list 😄 |
|
Ok, I spent too much time already implementing the Sabre stuff but not enough writing actual tests for GroupsManager 😄 Will do tomorrow so we can get this first PR merged soon. |
251b0e7
to
762497f
Compare
I've added unit tests now for the group backend and group manager. I've removed the DAV stuff from this PR into a separate PR: #7 Please review @DeepDiver1975 @jvillafanez |
762497f
to
d4b48b0
Compare
@DeepDiver1975 mind reviewing so I can continue with the DAV stuff ? Thanks |
/** | ||
* Manager for custom group | ||
*/ | ||
class CustomGroupsManager { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm questioning the purpose of this class... does it make the code too complex if we move this code to the backend?
Anyway, we should rename the class. The backend class will have a manager above (provided by core, where the backend will be added) and also below (this class) which is confusing. CustomGroupsDBHandler
seems a better choice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The purpose of the manager is to be used only by this one app to manage custom groups.
The backend itself only uses a subset of operations that it exposes to core because we don't want the users page to allow managing these, but we still want the search to work for the sharing autocomplete. Furthermore the backend class needs to work with core-style group ids (strings) while the manager works with this app's specific numeric id, so a conversion needs to be done.
I prefer to keep these separate to make the code clearer.
If I would move the extra operations to manage group members to the backend class as well, I don't want to expose this to the core interface. So we'd have two methods addToGroup
, one that is empty for the backend and another one that is only known by the customgroups app. That's not very clean and clear to understand.
Hope this clears it out a bit 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, got it, but I'd still rename the class to reduce confusion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you're right, this is more a database accessor. But we never used the name "DBHandler" before.
In core we used manager for "CommentsManager" and "SystemTagsManager" which do the same.
Some older call calls it "Mapper" like "TagMapper", but it's mostly because they use real objects instead of just arrays.
What do you think ?
<notnull>false</notnull> | ||
</field> | ||
<index> | ||
<name>cg_gid_uid_index</name> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if we should add another index only for the user_id. I expect the queries for groups will use this index, but I don't think the queries for users will.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I thought that this was the proper way to define multi-column primary unique keys ?
I copied this idea from core's group_user
table.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The multi-column index is fine because we want group_id + user_id be unique. I trust the DBMSs be smart enough to use this index when we query for group information, but I don't think this will happen for user information.
* Register the group manager | ||
*/ | ||
public function registerGroupBackend() { | ||
$backend = $this->getContainer()->query('\OCA\CustomGroups\CustomGroupsBackend'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know where this come from.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean ? This method is called in appinfo/app.php
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The \OCA\CustomGroups\CustomGroupsBackend
needs to be register in the container, but I don't know where this registration is made.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it doesn't. DI container power !
It works because the class name matches exactly so it's able to resolve it.
You only need explicit registration when the names different or when your constructor requires parameters that cannot be injected (ex: strings)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😮 👏
Restarted travis build now that master contains the code we need |
|
|
Looks like for the Mapper I can throw away almost all my code (and unit tests) and start over. I don't think the benefit of having the mapper pattern here is bringing any significant benefit at this point. (it might even introduce more hurdles for the API consumer) I'll abandon this approach and simply rename the manager to |
11f89fe
to
c2a442d
Compare
Raised #10 to use doctrine migrations for initial DB. I'd like to get this PR here merged so I can move forward with the Sabre plugins / API. That is, unless there is a no-go in this PR. |
397356c
to
bba7adc
Compare
Also, looks like sqlite not happy with my DB stuff. Will look into it. (Mysql worked fine) |
Something is wrong with the unique constraint. Looks like SQLite set the primary key only on "group_id" instead of both "group_id" + "user_id" 😢 |
primary key is only set on $table->setPrimaryKey(['group_id', 'user_id']); debugging.... |
grrr, this is the resulting SQL generated by Doctrine:
I didn't even ask for autoincrement... Looks like a Doctrine bug. We do have a table in core with a similar schema and that one looks correct:
so this means SQLite supports multi-column primary keys but Doctrine doesn't seem to be able to create that. Googling now, I hope there is maybe a missing flag or something in the API. |
Facepalm, I forgot to remove "autoincrement" when copy-pasting the definitions. |
bba7adc
to
f0b5648
Compare
@jvillafanez I fixed all your comments and additionally fixed the DB schema. |
@DeepDiver1975 can you create the repo for clover coverage ? https://travis-ci.org/owncloud/customgroups/jobs/183218691#L831 |
👍 |
I'm going to remove the code coverage thing for now and let @DeepDiver1975 sort it out separately. |
Raised here #12 |
c780116
to
d64a029
Compare
Implement group manager.
To test:
insert into oc_custom_group values (NULL, 'myfriends', 'My friends');
insert into oc_custom_group_member values (1, 'user2', 1);
insert into oc_custom_group_member values (1, 'user3', 0);
Some concerns:
@DeepDiver1975 @butonic @jvillafanez what do you think ?