Skip to content

Commit

Permalink
Merge pull request #1006 from France-ioi/1004
Browse files Browse the repository at this point in the history
Get permission service: clean "can_request_help" usage
  • Loading branch information
GeoffreyHuck committed Sep 13, 2023
2 parents cf941e6 + dd8741a commit 73c262c
Show file tree
Hide file tree
Showing 10 changed files with 758 additions and 256 deletions.
4 changes: 2 additions & 2 deletions app/api/groups/get_participant_progress.feature
Original file line number Diff line number Diff line change
Expand Up @@ -574,11 +574,11 @@ Feature: Display the current progress of a participant on children of an item (g
When I send a GET request to "/items/1020/participant-progress?as_team_id=14"
Then the response code should be 200
And the response at $.item.item_id should be "1020"
And the response should not be defined at $.children
And the response at $.children should be "<undefined>"

Scenario: Should not return the children when the current user doesn't have a started result on the requested item with watched_group_id
Given I am the user with id "22"
When I send a GET request to "/items/210/participant-progress?watched_group_id=67"
Then the response code should be 200
And the response at $.item.item_id should be "210"
And the response should not be defined at $.children
And the response at $.children should be "<undefined>"
210 changes: 140 additions & 70 deletions app/api/groups/get_permissions.feature

Large diffs are not rendered by default.

318 changes: 232 additions & 86 deletions app/api/groups/get_permissions.go

Large diffs are not rendered by default.

182 changes: 167 additions & 15 deletions app/api/groups/get_permissions_can_request_help_to.feature

Large diffs are not rendered by default.

45 changes: 36 additions & 9 deletions app/api/threads/list_threads.feature
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ Feature: List threads
| -latest_update_at | 2 | 2 | 0 | @TaskMaxUpdateAt |
| -latest_update_at | 2 | 2 | 1 | @TaskSecondMaxUpdateAt |

Scenario Outline: Should support pagination parameters
Scenario: Should support pagination parameters with results
Given I am @John
And there are the following items:
| item | type |
Expand All @@ -268,14 +268,25 @@ Feature: List threads
| @John | @TaskMinUpdateAt | 1 | 2023-01-01 00:00:01 |
| @John | @TaskMaxUpdateAt | 1 | 2023-01-01 00:00:02 |
And I am @John
When I send a GET request to "/threads?is_mine=1&limit=1&sort=latest_update_at&from.item_id=<from.item_id>&from.participant_id=<from.participant_id>"
When I send a GET request to "/threads?is_mine=1&limit=1&sort=latest_update_at&from.item_id=@TaskMinUpdateAt&from.participant_id=@John"
Then the response code should be 200
And the response should be a JSON array with <nb_results> entries
And the response at $[0].item.id should be "<result_item>"
Examples:
| from.item_id | from.participant_id | nb_results | result_item |
| @TaskMinUpdateAt | @John | 1 | @TaskMaxUpdateAt |
| @TaskMaxUpdateAt | @John | 0 | |
And the response should be a JSON array with 1 entries
And the response at $[0].item.id should be "@TaskMaxUpdateAt"

Scenario: Should support pagination parameters with no results
Given I am @John
And there are the following items:
| item | type |
| @TaskMinUpdateAt | Task |
| @TaskMaxUpdateAt | Task |
And there are the following threads:
| participant | item | visible_by_participant | latest_update_at |
| @John | @TaskMinUpdateAt | 1 | 2023-01-01 00:00:01 |
| @John | @TaskMaxUpdateAt | 1 | 2023-01-01 00:00:02 |
And I am @John
When I send a GET request to "/threads?is_mine=1&limit=1&sort=latest_update_at&from.item_id=@TaskMaxUpdateAt&from.participant_id=@John"
Then the response code should be 200
And the response should be a JSON array with 0 entries

Scenario Outline: Should filter by status if parameter status is given
Given I am @John
Expand Down Expand Up @@ -320,4 +331,20 @@ Feature: List threads
| latest_update_gt | first_result_item | nb_results |
| 2023-01-01T00:00:00Z | @Task1 | 3 |
| 2023-01-01T00:00:02Z | @Task3 | 1 |
| 2023-01-01T00:00:03Z | | 0 |

Scenario: Should return no results when latest_update_gt is given but no entries are greater than latest_update_gt
Given I am @John
And there are the following items:
| item | type |
| @Task1 | Task |
| @Task2 | Task |
| @Task3 | Task |
And there are the following threads:
| participant | item | visible_by_participant | latest_update_at |
| @John | @Task1 | 1 | 2023-01-01 00:00:01 |
| @John | @Task2 | 1 | 2023-01-01 00:00:02 |
| @John | @Task3 | 1 | 2023-01-01 00:00:03 |
And I am @John
When I send a GET request to "/threads?is_mine=1&latest_update_gt=2023-01-01T00:00:03Z&sort=latest_update_at"
Then the response code should be 200
And the response should be a JSON array with 0 entries
4 changes: 2 additions & 2 deletions app/database/item_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,8 @@ func (s *ItemStore) DeleteItem(itemID int64) (err error) {
})
}

// getAncestorsRequestHelpPropagationQuery gets all ancestors of an itemID while request_help_propagation = 1.
func (s *ItemStore) getAncestorsRequestHelpPropagationQuery(itemID int64) *DB {
// GetAncestorsRequestHelpPropagatedQuery gets all ancestors of an itemID while request_help_propagation = 1.
func (s *ItemStore) GetAncestorsRequestHelpPropagatedQuery(itemID int64) *DB {
return s.Raw(`
WITH RECURSIVE items_ancestors_request_help_propagation(item_id) AS
(
Expand Down
2 changes: 1 addition & 1 deletion app/database/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func (u *User) CanRequestHelpTo(s *DataStore, itemID, helperGroupID int64) bool
// one of the ancestors (including himself) of User has the can_request_help_to(Group) on Item,
// recursively on Item’s ancestors while request_help_propagation=1, for each Group being a descendant of Group.

itemAncestorsRequestHelpPropagationQuery := s.Items().getAncestorsRequestHelpPropagationQuery(itemID)
itemAncestorsRequestHelpPropagationQuery := s.Items().GetAncestorsRequestHelpPropagatedQuery(itemID)

canRequestHelpTo, err := s.Users().
Joins("JOIN groups_ancestors_active ON groups_ancestors_active.child_group_id = ?", u.GroupID).
Expand Down
3 changes: 2 additions & 1 deletion testhelpers/feature_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ func FeatureContext(s *godog.Suite) {
s.Step(`^there are the following items:$`, ctx.ThereAreTheFollowingItems)
s.Step(`^there are the following tasks:$`, ctx.ThereAreTheFollowingTasks)
s.Step(`^there are the following item permissions:$`, ctx.ThereAreTheFollowingItemPermissions)
s.Step(`^there are the following item relations:$`, ctx.ThereAreTheFollowingItemRelations)
s.Step(`^I can watch the group (@\w+)$`, ctx.ICanWatchGroup)
s.Step(`^I can watch the participant with id "([^"]*)"$`, ctx.ICanWatchGroupWithID)
s.Step(`^I can view (none|info|content|content_with_descendants|solution) on item with id "([^"]*)"$`,
Expand Down Expand Up @@ -83,7 +84,7 @@ func FeatureContext(s *godog.Suite) {
s.Step(`^the response should be a JSON array with (\d+) entr(ies|y)$`, ctx.ItShouldBeAJSONArrayWithEntries)
s.Step(`^the response at ([^ ]+) should be "([^"]*)"$`, ctx.TheResponseAtShouldBeTheValue)
s.Step("^the response at ([^ ]+) should be:$", ctx.TheResponseAtShouldBe)
s.Step("^the response should not be defined at ([^ ]+)$", ctx.TheResponseShouldNotBeDefinedAt)
s.Step("^the response at ([^ ]+) in JSON should be:$", ctx.TheResponseAtInJSONShouldBe)

s.Step(`^the table "([^"]*)" should be:$`, ctx.TableShouldBe)
s.Step(`^the table "([^"]*)" should be empty$`, ctx.TableShouldBeEmpty)
Expand Down
113 changes: 105 additions & 8 deletions testhelpers/steps_app_language.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ const (
strTrue = "true"
)

var itemPermissionKeys = []string{"can_view", "can_grant_view", "can_watch", "can_edit", "is_owner", "can_request_help_to"}
var (
itemPermissionKeys = []string{"can_view", "can_grant_view", "can_watch", "can_edit", "is_owner", "can_request_help_to"}
itemPropagationKeys = []string{"grant_view_propagation", "watch_propagation", "edit_propagation", "request_help_propagation"}
)

// ctx.getParameterMap parses parameters in format key1=val1,key2=val2,... into a map.
func (ctx *TestContext) getParameterMap(parameters string) map[string]string {
Expand Down Expand Up @@ -257,23 +260,34 @@ func (ctx *TestContext) addGroupManager(manager, group, canWatchMembers, canGran
}

// addPermissionsGranted adds a permission granted in the database.
func (ctx *TestContext) addPermissionGranted(group, item, permission, permissionValue string) {
func (ctx *TestContext) addPermissionGranted(group, item, sourceGroup, origin, permission, permissionValue string) {
groupID := ctx.getReference(group)
sourceGroupID := ctx.getReference(sourceGroup)
itemID := ctx.getReference(item)

permissionsGrantedTable := "permissions_granted"
key := strconv.FormatInt(groupID, 10) + "," + strconv.FormatInt(itemID, 10)
key := strconv.FormatInt(groupID, 10) + "," +
strconv.FormatInt(itemID, 10) + "," +
strconv.FormatInt(sourceGroupID, 10) + "," +
origin

if !ctx.isInDatabase(permissionsGrantedTable, key) {
ctx.addInDatabase(permissionsGrantedTable, key, map[string]interface{}{
"group_id": groupID,
"source_group_id": groupID,
"source_group_id": sourceGroupID,
"item_id": itemID,
"origin": origin,
})
}

if permission == "can_request_help_to" {
permissionValue = strconv.FormatInt(ctx.getReference(permissionValue), 10)
canRequestHelpToGroupID := strconv.FormatInt(ctx.getReference(permissionValue), 10)

if !ctx.isInDatabase("groups", canRequestHelpToGroupID) {
ctx.addGroup(permissionValue, "Group "+referenceToName(permissionValue), "Class")
}

permissionValue = canRequestHelpToGroupID
}

if permission == "is_owner" {
Expand Down Expand Up @@ -320,14 +334,18 @@ func (ctx *TestContext) addResult(attemptID, participant, item string, validated
)
}

func (ctx *TestContext) getItemItemKey(parentItemID, childItemID int64) string {
return strconv.FormatInt(parentItemID, 10) + "," + strconv.FormatInt(childItemID, 10)
}

// addItemItem adds an item-item in the database.
func (ctx *TestContext) addItemItem(parentItem, childItem string) {
parentItemID := ctx.getReference(parentItem)
childItemID := ctx.getReference(childItem)

ctx.addInDatabase(
"items_items",
strconv.FormatInt(parentItemID, 10)+","+strconv.FormatInt(childItemID, 10),
ctx.getItemItemKey(parentItemID, childItemID),
map[string]interface{}{
"parent_item_id": parentItemID,
"child_item_id": childItemID,
Expand All @@ -336,6 +354,12 @@ func (ctx *TestContext) addItemItem(parentItem, childItem string) {
)
}

func (ctx *TestContext) addItemItemPropagation(parent, child, propagation, propagationValue string) {
key := ctx.getItemItemKey(ctx.getReference(parent), ctx.getReference(child))

ctx.dbTables["items_items"][key][propagation] = propagationValue
}

// addItem adds an item in the database.
func (ctx *TestContext) addItem(fields map[string]string) {
dbFields := make(map[string]interface{})
Expand Down Expand Up @@ -693,9 +717,26 @@ func (ctx *TestContext) ThereAreTheFollowingItemPermissions(itemPermissions *mes
}

func (ctx *TestContext) applyUserPermissionsOnItem(itemPermission map[string]string) error {
sourceGroup := itemPermission["group"]
if definedSourceGroup, ok := itemPermission["source_group"]; ok {
sourceGroup = definedSourceGroup
}

origin := "group_membership"
if definedOrigin, ok := itemPermission["origin"]; ok {
origin = definedOrigin
}

for _, permissionKey := range itemPermissionKeys {
if permissionValue, ok := itemPermission[permissionKey]; ok {
err := ctx.UserSetPermissionOnItemWithID(permissionKey, permissionValue, itemPermission["group"], itemPermission["item"])
err := ctx.UserSetPermissionExtendedOnItemWithID(
permissionKey,
permissionValue,
itemPermission["group"],
itemPermission["item"],
sourceGroup,
origin,
)
if err != nil {
return err
}
Expand All @@ -705,6 +746,48 @@ func (ctx *TestContext) applyUserPermissionsOnItem(itemPermission map[string]str
return nil
}

// ThereAreTheFollowingItemRelations defines item relations, in items_items table.
func (ctx *TestContext) ThereAreTheFollowingItemRelations(itemPermissions *messages.PickleStepArgument_PickleTable) error {
for i := 1; i < len(itemPermissions.Rows); i++ {
itemRelation := ctx.getRowMap(i, itemPermissions)

err := ctx.applyItemRelation(itemRelation)
if err != nil {
return err
}
}

return nil
}

func (ctx *TestContext) applyItemRelation(itemRelation map[string]string) error {
ctx.addItemItem(itemRelation["parent"], itemRelation["item"])

for _, propagationKey := range itemPropagationKeys {
if propagationValue, ok := itemRelation[propagationKey]; ok {
boolValue, err := strconv.ParseBool(propagationValue)
if err != nil {
panic(fmt.Sprintf("applyItemRelation: %v cannot be parsed as a boolean", boolValue))
}

if boolValue {
propagationValue = "1"
} else {
propagationValue = "0"
}

ctx.addItemItemPropagation(
itemRelation["parent"],
itemRelation["item"],
propagationKey,
propagationValue,
)
}
}

return nil
}

// ICanWatchGroup adds the permission for the user to watch a group.
func (ctx *TestContext) ICanWatchGroup(groupName string) error {
return ctx.UserIsAManagerOfTheGroupWith(getParameterString(map[string]string{
Expand Down Expand Up @@ -816,9 +899,23 @@ func (ctx *TestContext) IAmAMemberOfTheGroup(name string) error {
return ctx.IAmAMemberOfTheGroupWithID(name)
}

// ItemRelationSetPropagation adds a propagation on an item relation.
func (ctx *TestContext) ItemRelationSetPropagation(propagation, value, parent, item string) error {
ctx.addItemItemPropagation(parent, item, propagation, value)

return nil
}

// UserSetPermissionExtendedOnItemWithID gives a user a permission on an item with a specific source_group and origin.
func (ctx *TestContext) UserSetPermissionExtendedOnItemWithID(permission, value, user, item, sourceGroup, origin string) error {
ctx.addPermissionGranted(user, item, sourceGroup, origin, permission, value)

return nil
}

// UserSetPermissionOnItemWithID gives a user a permission on an item.
func (ctx *TestContext) UserSetPermissionOnItemWithID(permission, value, user, item string) error {
ctx.addPermissionGranted(user, item, permission, value)
ctx.addPermissionGranted(user, item, user, "group_membership", permission, value)

return nil
}
Expand Down
Loading

0 comments on commit 73c262c

Please sign in to comment.