From df5d3ee5476cdf7e547fdcbc958a982fb89411ea Mon Sep 17 00:00:00 2001 From: Ryan Oberlander <46940735+roberlander2@users.noreply.github.com> Date: Fri, 3 Jan 2025 15:06:21 -0600 Subject: [PATCH] Update develop (#7) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [#447] Groups BB rapid fixes and improvements (#449) * Ability to filter authman/manged groups [#441] * Admin APIs * Drop wrong logic related to the CanSendPostToAdmins flag * Rebuild api doc * Fix and rebuild * Update libraries * v1.38.0 * [#450] Improve group events APIs (#451) * [#450] Improve group events APIs * Rebuild api doc * v1.39.0 * [#452] Improve create group admin api (#453) Improve create group admin api #452 * v1.40.0 * [#452] improve create group admin api (#454) * Improve create group admin api #452 * [#452] Additional fix and cleanup * v1.40.1 * [#460] Fix missing member name and email for a managed group auto sync task (#461) * v1.40.2 * [#459] Introduce BBs APIs. Implement aggregate event users. (#462) * Introduce BBs APIs * Permissions. Part 1 * Report group as abuse * Introduce Auth2 for upcoming major refactoring in the near future * More fixes * Fix the policy * Resolve lint issues * Change log * v1.41.0 * Minor build fix * [ID-463]Delete everything from the database related to the core account (#464) * set the Changelog.md * in progress * in progress * delete group memberships * delete the users * delete posts * no message * pull members from event * fixes * delete members from posts * put in transaction * Make fixes. Improve the cron scheduler. Fix the index issue --------- Co-authored-by: Stefan Vitanov Co-authored-by: Mladen Dryankov * [#465] Add new permissions for managing group events independently for granтing access (#466) Add new permissions for managing group events independently for granting access [#465] * v1.42.0 * [#465] add new role for managing group events (#467) * Add new permissions for managing group events independently for granting access [#465] * Updated golang & alpine Docker container versions * [#456] Create Group Report Abuse API (#470) Create Group Report Abuse API [#456] * rovide Replies when loading single Post. Part 1 * Small fix * Fix and improve transactions handling * safety measure * [#468] provide nested replies single post api (#471) * rovide Replies when loading single Post. Part 1 * Small fix * Fix and improve transactions handling * safety measure * v1.43.0 * [#457] Include sender, post content and action in group post notification body (#472) Include sender, post content and action in group post notification body [#457] Send post notification only to the creator of the post [#372] * v1.44.0 * Use all_bbs_groups permissions for all BBs APIs [#473] * v1.45.0 * [#473] Use all_bbs_groups & get_aggregated-users permissions for BBs APIs (Additional change) (#474) Use all_bbs_groups & get_aggregated-users permissions for BBs APIs (Additional change) [#473] * 1.45.1 * Update direct messages notification pattern [#475] (#476) * 1.45.2 * [#458] Admin API for adding group members by NetIDs #458 (#478) * Prepare admin logic * More improvements and local fixes * More fixes and improvements * Changelog * Regenerate docs * Fix typo * Redo wrong commit * v1.46.0 * [#477] Do not send polls and direct message notifications as muted when they are not (#479) * [#477] Do not send polls and direct message notifications as muted when they are not * Gen api doc * v1.46.1 * [#457] Additional fix: Truncate the post body to 250 characters within the notification (#480) * Include sender, post content and action in group post notification body [#457] Send post notification only to the creator of the post [#372] * [#457] Additional fix: Truncate the post body to 250 characters within the notification * v1.46.2 * [#481] Use "get_groups" permission for loading user groups in the admin API (#482) Use "get_groups" permission for loading user groups in the admin API [#481] * v1.46.3 * [ID-455]POST request for loading group members (#486) * add the Changelog.md * add GetGroupMemenrsV2 POST * Fix swagger and apidoc --------- Co-authored-by: Stefan Vitanov Co-authored-by: Mladen Dryankov * [ID-483]Groups Stats are not updated (#487) * add the Changelog.md * add update groups stats to the create and delete membership --------- Co-authored-by: Stefan Vitanov * [ID-485]The value for "current_member" is not available in group json (#488) * set the Changelog.md * set current user to GetGroups --------- Co-authored-by: Stefan Vitanov * update version to 1.48.0 * hotfix * [ID-490]Fix Groups Stats are not updated (#492) * set the Changelog.md * fix UpdateGroupStats function fro create and delete group member --------- Co-authored-by: Stefan Vitanov * [#484] Approve all api (#491) * Main implementation * Final implementation * Update apidoc * update version to 1.48.0 * [ID-494]BBs Api for getting group memberships (#495) * set the Changelog.md * set the docs * Gets all related group memberships status and group title using userID * set the goupID in the response and set the permission * fix * fix FindGroupMembershipStatusAmdGroupTitle using Aggregation * fix the comments * Revert "fix the comments" This reverts commit a054f6ea2e9b51fe78a627b0f24d3a733a730573. --------- Co-authored-by: Stefan Vitanov * update version to 1.49.0 * [ID-497] (#498) * set the Changelog.md * fix the aggregation pipeline --------- Co-authored-by: Stefan Vitanov * [ID-500] Add "group_id" to the bbs get group membership API (#501) * add the Changelog.md * add the groupID to the response --------- Co-authored-by: Stefan Vitanov * update version to 1.49.0 * [ID-503]Calendar events issues (#504) * set the Changelog.md * in progress * set bbs get events API using comma separated eventIDs * add groupIDs to CreateCalendarEvent bbs api * fix --------- Co-authored-by: Stefan Vitanov * update the version to 1.51.0 * fix date * merge develop into main (#505) * [ID-503]Calendar events issues (#504) * set the Changelog.md * in progress * set bbs get events API using comma separated eventIDs * add groupIDs to CreateCalendarEvent bbs api * fix --------- Co-authored-by: Stefan Vitanov * update the version to 1.51.0 * fix date --------- Co-authored-by: Stefan Vitanov * [#509] Bad Authman sync for user who has alternative auth method for first login (#510) Bad Authman sync for user who has alternative auth method for first login [#509] * v1.51.1 * [#506] New Event notifications are not sent to Group members (#511) * New Event notifications are not sent to Group members [#506] * Add missed notification * v1.52.0 * [ID-513] FERPA issues for group memberships (#514) * set the Changelog.md * in progress * if ferpa account is true than all the fileds are emty string or nil for admin/group/{group-id}/members * fix the core function * fix comment * set protectByFerpa function --------- Co-authored-by: Stefan Vitanov * update the version to 1.53.0 * [ID-517]Get groups membership by groupID BBs (#517) * add the Changelog.md * set the docs * add the permission * structure the API * add get user memberships by groupID --------- Co-authored-by: Stefan Vitanov * update the version to 1.54.0 * [ID-521]BBs API to Get groups by group_ids (#522) * set the Changelog.md * set the get groups by groups id API * fix lint issue --------- Co-authored-by: Stefan Vitanov * update version to 1.55.0 --------- Co-authored-by: Mladen Dryankov Co-authored-by: stefanvitanov <75947010+stefanvit@users.noreply.github.com> Co-authored-by: Stefan Vitanov --- CHANGELOG.md | 8 +++ SECURITY.md | 4 +- core/interfaces.go | 13 +++++ core/services_events.go | 7 +++ docs/swagger.yaml | 35 +++++------ driven/storage/adapter_events.go | 40 +++++++++++++ driver/web/adapter.go | 2 + .../authorization_bbs_permission_policy.csv | 1 + driver/web/rest/bbapis.go | 58 +++++++++++++++++++ 9 files changed, 147 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 658bacc..1ec1e5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add CORS support +## [1.55.0] - 2024-11-13 +### Added +- BBs API to Get groups by group_ids [#521] (https://github.com/rokwire/groups-building-block/issues/521) + +## [1.54.0] - 2024-10-29 +### Added +- Get groups membership by groupID BBs [#516] (https://github.com/rokwire/groups-building-block/issues/516) + ## [1.53.0] - 2024-10-22 ### Added - FERPA issues for group memberships [#513](https://github.com/rokwire/groups-building-block/issues/513) diff --git a/SECURITY.md b/SECURITY.md index aff1143..8261f84 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -6,8 +6,8 @@ Patches for **Groups Building Block** in this repository will only be applied to | Version | Supported | | ------- | ------------------ | -| 1.51.0 | :white_check_mark: | -| <1.51.0 | :red_cross_mark: | +| 1.55.0 | :white_check_mark: | +| <1.55.0 | :red_cross_mark: | diff --git a/core/interfaces.go b/core/interfaces.go index e31ddd7..98f3c6f 100644 --- a/core/interfaces.go +++ b/core/interfaces.go @@ -44,6 +44,8 @@ type Services interface { ReportGroupAsAbuse(clientID string, current *model.User, group *model.Group, comment string) error GetGroup(clientID string, current *model.User, id string) (*model.Group, error) + GetGroupsByGroupIDs(groupIDs []string) ([]model.Group, error) + GetGroupStats(clientID string, id string) (*model.GroupStats, error) ApplyMembershipApproval(clientID string, current *model.User, membershipID string, approve bool, rejectReason string) error @@ -56,6 +58,8 @@ type Services interface { DeleteEvent(clientID string, current *model.User, eventID string, groupID string) error GetEventUserIDs(eventID string) ([]string, error) GetGroupMembershipsStatusAndGroupTitle(userID string) ([]model.GetGroupMembershipsResponse, error) + GetGroupMembershipsByGroupID(groupID string) ([]string, error) + GetGroupsEvents(eventIDs []string) ([]model.GetGroupsEvents, error) GetPosts(clientID string, current *model.User, filter model.PostsFilter, filterPrivatePostsValue *bool, filterByToMembers bool) ([]model.Post, error) @@ -211,10 +215,16 @@ func (s *servicesImpl) GetEventUserIDs(eventID string) ([]string, error) { func (s *servicesImpl) GetGroupMembershipsStatusAndGroupTitle(userID string) ([]model.GetGroupMembershipsResponse, error) { return s.app.findGroupMembershipsStatusAndGroupsTitle(userID) } +func (s *servicesImpl) GetGroupMembershipsByGroupID(groupID string) ([]string, error) { + return s.app.findGroupMembershipsByGroupID(groupID) +} func (s *servicesImpl) GetGroupsEvents(eventIDs []string) ([]model.GetGroupsEvents, error) { return s.app.findGroupsEvents(eventIDs) } +func (s *servicesImpl) GetGroupsByGroupIDs(groupIDs []string) ([]model.Group, error) { + return s.app.findGroupsByGroupIDs(groupIDs) +} func (s *servicesImpl) GetPosts(clientID string, current *model.User, filter model.PostsFilter, filterPrivatePostsValue *bool, filterByToMembers bool) ([]model.Post, error) { return s.app.getPosts(clientID, current, filter, filterPrivatePostsValue, filterByToMembers) @@ -419,6 +429,7 @@ type Storage interface { FindGroup(context storage.TransactionContext, clientID string, groupID string, userID *string) (*model.Group, error) FindGroupByTitle(clientID string, title string) (*model.Group, error) FindGroups(clientID string, userID *string, filter model.GroupsFilter) ([]model.Group, error) + FindGroupsByGroupIDs(groupIDs []string) ([]model.Group, error) FindUserGroups(clientID string, userID string, filter model.GroupsFilter) ([]model.Group, error) FindUserGroupsCount(clientID string, userID string) (*int64, error) DeleteUsersByAccountsIDs(log *logs.Logger, context storage.TransactionContext, accountsIDs []string) error @@ -431,6 +442,8 @@ type Storage interface { FindEventUserIDs(context storage.TransactionContext, eventID string) ([]string, error) FindGroupMembershipStatusAndGroupTitle(context storage.TransactionContext, userID string) ([]model.GetGroupMembershipsResponse, error) + FindGroupMembershipByGroupID(context storage.TransactionContext, groupID string) ([]string, error) + FindGroupsEvents(context storage.TransactionContext, eventIDs []string) ([]model.GetGroupsEvents, error) ReportGroupAsAbuse(clientID string, userID string, group *model.Group) error diff --git a/core/services_events.go b/core/services_events.go index fcf0b42..e0fc37e 100644 --- a/core/services_events.go +++ b/core/services_events.go @@ -39,10 +39,17 @@ func (app *Application) findGroupMembershipsStatusAndGroupsTitle(userID string) return app.storage.FindGroupMembershipStatusAndGroupTitle(nil, userID) } +func (app *Application) findGroupMembershipsByGroupID(groupID string) ([]string, error) { + return app.storage.FindGroupMembershipByGroupID(nil, groupID) +} func (app *Application) findGroupsEvents(eventIDs []string) ([]model.GetGroupsEvents, error) { return app.storage.FindGroupsEvents(nil, eventIDs) } +func (app *Application) findGroupsByGroupIDs(groupIDs []string) ([]model.Group, error) { + return app.storage.FindGroupsByGroupIDs(groupIDs) +} + func (app *Application) getEvents(clientID string, current *model.User, groupID string, filterByToMembers bool) ([]model.Event, error) { events, err := app.storage.FindEvents(clientID, current, groupID, filterByToMembers) if err != nil { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 8c29b63..1f7843c 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -2122,29 +2122,26 @@ paths: - IntAPIKeyAuth: [] tags: - Analytics - /api/bbs/groups/{user_id}/memberships: - get: - description: Gets all related group memberships status and group title using - userID - operationId: GetGroupMemberships - parameters: - - description: User ID + /api/bbs/groups/{group_id}/memberships: + get: + description: Gets an array of user IDs for all members in the group specified by groupID + operationId: GetGroupMembershipUserIds + parameters: + - description: Group ID in: path - name: user_id + name: group_id required: true type: string - responses: - "200": - description: OK - schema: - items: - items: - $ref: '#/definitions/GetGroupMembershipsResponse' - type: array - type: array - security: + responses: + "200": + description: OK + schema: + type: array + items: + type: string + security: - AppUserAuth: [] - tags: + tags: - BBS /api/group/{group-id}/authman/synchronize: post: diff --git a/driven/storage/adapter_events.go b/driven/storage/adapter_events.go index 397f3e4..2a66075 100644 --- a/driven/storage/adapter_events.go +++ b/driven/storage/adapter_events.go @@ -266,6 +266,29 @@ func (sa *Adapter) FindGroupMembershipStatusAndGroupTitle(context TransactionCon return results, nil } +// FindGroupMembershipByGroupID Find group membership ids +func (sa *Adapter) FindGroupMembershipByGroupID(context TransactionContext, groupID string) ([]string, error) { + filter := bson.D{primitive.E{Key: "group_id", Value: groupID}} + + // Define the results slice + var results []model.GroupMembership + + // Execute the aggregation pipeline + err := sa.db.groupMemberships.FindWithContext(context, filter, &results, nil) + if err != nil { + return nil, err + } + + var userIDs []string + for _, u := range results { + if u.UserID != "" { + userIDs = append(userIDs, u.UserID) + } + } + + return userIDs, nil +} + // FindGroupsEvents Find group ID and event ID func (sa *Adapter) FindGroupsEvents(context TransactionContext, eventIDs []string) ([]model.GetGroupsEvents, error) { filter := bson.D{} @@ -282,3 +305,20 @@ func (sa *Adapter) FindGroupsEvents(context TransactionContext, eventIDs []strin return groupsEvents, nil } + +// FindGroupsByGroupIDs Find group by group ID +func (sa *Adapter) FindGroupsByGroupIDs(groupIDs []string) ([]model.Group, error) { + filter := bson.D{} + + if len(groupIDs) > 0 { + filter = append(filter, bson.E{Key: "_id", Value: bson.M{"$in": groupIDs}}) + } + + var groups []model.Group + err := sa.db.groups.Find(filter, &groups, nil) + if err != nil { + return nil, errors.WrapErrorAction(logutils.ActionFind, "groups", nil, err) + } + + return groups, nil +} diff --git a/driver/web/adapter.go b/driver/web/adapter.go index 6340f3c..c0262be 100644 --- a/driver/web/adapter.go +++ b/driver/web/adapter.go @@ -206,7 +206,9 @@ func (we *Adapter) Start() { bbsSubrouter := restSubrouter.PathPrefix("/bbs").Subrouter() bbsSubrouter.HandleFunc("/event/{event_id}/aggregated-users", we.wrapFunc(we.bbsAPIHandler.GetEventUserIDs, we.auth2.bbs.Permissions)).Methods("GET") bbsSubrouter.HandleFunc("/groups/{user_id}/memberships", we.wrapFunc(we.bbsAPIHandler.GetGroupMemberships, we.auth2.bbs.Permissions)).Methods("GET") + bbsSubrouter.HandleFunc("/groups/{group_id}/group-memberships", we.wrapFunc(we.bbsAPIHandler.GetGroupMembershipsByGroupID, we.auth2.bbs.Permissions)).Methods("GET") bbsSubrouter.HandleFunc("/groups/events", we.wrapFunc(we.bbsAPIHandler.GetGroupsEvents, we.auth2.bbs.Permissions)).Methods("GET") + bbsSubrouter.HandleFunc("/groups", we.wrapFunc(we.bbsAPIHandler.GetGroupsByGroupIDs, we.auth2.bbs.Permissions)).Methods("GET") var handler http.Handler = router if len(we.corsAllowedOrigins) > 0 { diff --git a/driver/web/authorization_bbs_permission_policy.csv b/driver/web/authorization_bbs_permission_policy.csv index cc30a45..dcf4cb6 100644 --- a/driver/web/authorization_bbs_permission_policy.csv +++ b/driver/web/authorization_bbs_permission_policy.csv @@ -2,4 +2,5 @@ p, all_bbs_groups, /gr/api/bbs/*, (GET)|(POST)|(PUT)|(DELETE), All BBs APIs p, get_aggregated-users, /gr/api/bbs/event/*/aggregated-users, (GET), Get event group users (aggregated) p, get_user_membership, /gr/api/bbs/groups/*/memberships, (GET), Gets all related group memberships status and group title using userID +p, get_user_membership, /gr/api/bbs/groups/*/group-memberships, (GET), Gets all related group memberships status and group title using groupID p, get_groups_events, /gr/api/bbs/groups/events*, (GET), Gets all related eventID and groupID using eventIDs diff --git a/driver/web/rest/bbapis.go b/driver/web/rest/bbapis.go index 3034b6c..b1a5860 100644 --- a/driver/web/rest/bbapis.go +++ b/driver/web/rest/bbapis.go @@ -80,6 +80,34 @@ func (h *BBSApisHandler) GetGroupMemberships(log *logs.Log, req *http.Request, u } +// GetGroupMembershipsByGroupID Gets all related group memberships status and group title using groupID +// @Description Gets all related group memberships status and group title using groupID +// @ID GetGroupMembershipsByGroupID +// @Tags BBS +// @Param group_id path string true "Group ID" +// @Success 200 {array} []string +// @Security AppUserAuth +// @Router /api/bbs/groups/{group_id}/group-memberships [get] +func (h *BBSApisHandler) GetGroupMembershipsByGroupID(log *logs.Log, req *http.Request, user *model.User) logs.HTTPResponse { + params := mux.Vars(req) + groupID := params["group_id"] + if len(groupID) <= 0 { + return log.HTTPResponseErrorAction(logutils.ActionGet, logutils.TypePathParam, nil, errors.New("missing group_id"), http.StatusBadRequest, false) + } + groupMembershipsIDs, err := h.app.Services.GetGroupMembershipsByGroupID(groupID) + if err != nil { + return log.HTTPResponseErrorAction(logutils.ActionGet, logutils.TypeError, nil, err, http.StatusBadRequest, false) + } + + data, err := json.Marshal(groupMembershipsIDs) + if err != nil { + return log.HTTPResponseErrorAction(logutils.ActionGet, logutils.TypeError, nil, err, http.StatusBadRequest, false) + } + + return log.HTTPResponseSuccessJSON(data) + +} + // GetGroupsEvents Gets all related eventID and groupID using eventIDs // @Description Gets all related eventID and groupID using eventIDs // @ID GetGroupsEvents @@ -106,3 +134,33 @@ func (h *BBSApisHandler) GetGroupsEvents(log *logs.Log, req *http.Request, user return log.HTTPResponseSuccessJSON(data) } + +// GetGroupsByGroupIDs Gets all related groups by groupIDs +// @Description Gets all related groups by groupIDs +// @ID GetGroupsbyGroupsIDs +// @Tags BBS +// @Param comma separated groupIDs query +// @Success 200 {array} []model.Group +// @Security AppUserAuth +// @Router /api/bbs/groups [get] +func (h *BBSApisHandler) GetGroupsByGroupIDs(log *logs.Log, req *http.Request, user *model.User) logs.HTTPResponse { + var groupIDs []string + groupArg := req.URL.Query().Get("group-ids") + if len(groupArg) <= 0 { + return log.HTTPResponseErrorAction(logutils.ActionGet, logutils.TypeQueryParam, nil, errors.New("missing group_ids"), http.StatusBadRequest, false) + } + if groupArg != "" { + groupIDs = strings.Split(groupArg, ",") + } + groups, err := h.app.Services.GetGroupsByGroupIDs(groupIDs) + if err != nil { + return log.HTTPResponseErrorAction(logutils.ActionGet, logutils.TypeError, nil, err, http.StatusBadRequest, false) + } + data, err := json.Marshal(groups) + if err != nil { + return log.HTTPResponseErrorAction(logutils.ActionGet, logutils.TypeError, nil, err, http.StatusBadRequest, false) + } + + return log.HTTPResponseSuccessJSON(data) + +}