diff --git a/api/openapi.json b/api/openapi.json index 490bf71..982ebfd 100644 --- a/api/openapi.json +++ b/api/openapi.json @@ -1014,6 +1014,537 @@ } } } + }, + "delete": { + "summary": "Delete relationship between two persons", + "operationId": "deleteRelationship", + "parameters": [ + { + "name": "id1", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "id2", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "X-User-ID", + "in": "header", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Relationship deleted", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + } + } + } + + }, + "/admin/{id1}": { + "get": { + "summary": "Get profile Admins", + "operationId": "getProfileAdmins", + "parameters": [ + { + "name": "id1", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "X-User-ID", + "in": "header", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Admins retrieved", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "admins": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OptimizedPersonNode" + } + } + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/admin/{id1}/{id2}": { + "get": { + "summary": "Get admin relationship between two persons", + "operationId": "getAdminRelationship", + "parameters": [ + { + "name": "id1", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "id2", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "X-User-ID", + "in": "header", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Admin retrieved", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Admin" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + } + } + }, + "post": { + "summary": "Create admin relationship between two persons", + "operationId": "createAdminRelationship", + "parameters": [ + { + "name": "id1", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "id2", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "X-User-ID", + "in": "header", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Admin created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Admin" + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + } + } + }, + "delete":{ + "summary": "Delete admin relationship between two persons", + "operationId": "deleteAdminRelationship", + "parameters": [ + { + "name": "id1", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "id2", + "in": "path", + "required": true, + "schema": { + "type": "integer" + } + }, + { + "name": "X-User-ID", + "in": "header", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Admin deleted", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + } + } + } + }, + "/managed_profiles": { + "get": { + "summary": "Get managed profiles", + "operationId": "getManagedProfiles", + "parameters": [ + { + "name": "X-User-ID", + "in": "header", + "required": true, + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "description": "Managed Profiles retrieved", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "admins": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OptimizedPersonNode" + } + } + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "msg": { + "type": "string" + } + } + } + } + } + } + } } }, "/recipe/{id}": { @@ -1977,7 +2508,12 @@ "type": "string", "format": "date", "nullable": true + }, + "profile_picture":{ + "type": "string", + "nullable": true } + } }, "FamilyTree": { @@ -2162,7 +2698,12 @@ "type": "string" }, "properties": { - "type": "object" + "type": "object", + "properties": { + "added": { + "type": "integer" + } + } } } } diff --git a/apps/app/src/lib/api/api.gen.ts b/apps/app/src/lib/api/api.gen.ts index f691849..612ee46 100644 --- a/apps/app/src/lib/api/api.gen.ts +++ b/apps/app/src/lib/api/api.gen.ts @@ -62,7 +62,8 @@ export interface paths { path?: never; cookie?: never; }; - get?: never; + /** Get a person by ID */ + get: operations["getPersonById"]; put?: never; post?: never; /** Soft delete a person by ID */ @@ -171,6 +172,60 @@ export interface paths { get: operations["getRelationship"]; put?: never; post?: never; + /** Delete relationship between two persons */ + delete: operations["deleteRelationship"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/admin/{id1}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get profile Admins */ + get: operations["getProfileAdmins"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/admin/{id1}/{id2}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get admin relationship between two persons */ + get: operations["getAdminRelationship"]; + put?: never; + /** Create admin relationship between two persons */ + post: operations["createAdminRelationship"]; + /** Delete admin relationship between two persons */ + delete: operations["deleteAdminRelationship"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/managed_profiles": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get managed profiles */ + get: operations["getManagedProfiles"]; + put?: never; + post?: never; delete?: never; options?: never; head?: never; @@ -235,10 +290,6 @@ export type webhooks = Record; export interface components { schemas: { PersonProperties: { - allow_admin_access?: { - id?: number; - name?: string; - }[] | null; invite_code?: string | null; google_id?: string | null; first_name?: string | null; @@ -385,6 +436,7 @@ export interface components { born?: string; /** Format: date */ died?: string | null; + profile_picture?: string | null; }; FamilyTree: { ancestors?: components["schemas"]["OptimizedPersonNode"][]; @@ -433,6 +485,15 @@ export interface components { like_it?: boolean | null; could_make_it?: boolean | null; }; + Admin: { + id?: number; + label?: string; + start?: string; + end?: string; + properties?: { + added?: number; + }; + }; }; responses: never; parameters: never; @@ -490,6 +551,8 @@ export interface operations { content: { "application/json": { person: components["schemas"]["PersonRegistration"]; + /** @enum {string} */ + type?: "child" | "parent" | "spouse" | "sibling"; relationship: components["schemas"]["FamilyRelationship"]; }; }; @@ -534,7 +597,10 @@ export interface operations { createPerson: { parameters: { query?: never; - header?: never; + header: { + "X-User-ID": number; + "X-User-Name": string; + }; path?: never; cookie?: never; }; @@ -553,8 +619,43 @@ export interface operations { "application/json": components["schemas"]["Person"]; }; }; - /** @description Unauthorized */ - 401: { + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + }; + }; + getPersonById: { + parameters: { + query?: never; + header: { + "X-User-ID": number; + }; + path: { + id: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Person retrieved */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Person"]; + }; + }; + /** @description Bad request */ + 400: { headers: { [name: string]: unknown; }; @@ -768,6 +869,17 @@ export interface operations { }; }; }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; }; }; createPersonByGoogleId: { @@ -805,6 +917,17 @@ export interface operations { }; }; }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; }; }; createPersonByGoogleIdAndInviteCode: { @@ -965,6 +1088,8 @@ export interface operations { "application/json": { id1?: string; id2?: string; + /** @enum {string} */ + type?: "child" | "parent" | "spouse" | "sibling"; relationship?: components["schemas"]["FamilyRelationship"]; }; }; @@ -1061,6 +1186,358 @@ export interface operations { }; }; }; + deleteRelationship: { + parameters: { + query?: never; + header: { + "X-User-ID": number; + }; + path: { + id1: number; + id2: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Relationship deleted */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + }; + }; + getProfileAdmins: { + parameters: { + query?: never; + header: { + "X-User-ID": number; + }; + path: { + id1: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Admins retrieved */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + admins?: components["schemas"]["OptimizedPersonNode"][]; + }; + }; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + }; + }; + getAdminRelationship: { + parameters: { + query?: never; + header: { + "X-User-ID": number; + }; + path: { + id1: number; + id2: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Admin retrieved */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Admin"]; + }; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + }; + }; + createAdminRelationship: { + parameters: { + query?: never; + header: { + "X-User-ID": number; + }; + path: { + id1: number; + id2: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Admin created */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["Admin"]; + }; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + }; + }; + deleteAdminRelationship: { + parameters: { + query?: never; + header: { + "X-User-ID": number; + }; + path: { + id1: number; + id2: number; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Admin deleted */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + }; + }; + getManagedProfiles: { + parameters: { + query?: never; + header: { + "X-User-ID": number; + }; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Managed Profiles retrieved */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + admins?: components["schemas"]["OptimizedPersonNode"][]; + }; + }; + }; + /** @description Bad request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": { + msg?: string; + }; + }; + }; + }; + }; softDeleteRecipe: { parameters: { query?: never; diff --git a/apps/db-adapter/internal/api/admin.go b/apps/db-adapter/internal/api/admin.go new file mode 100644 index 0000000..385547b --- /dev/null +++ b/apps/db-adapter/internal/api/admin.go @@ -0,0 +1,130 @@ +package api + +import ( + "context" + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/vcscsvcscs/GenerationsHeritage/apps/db-adapter/internal/api/auth" + "github.com/vcscsvcscs/GenerationsHeritage/apps/db-adapter/internal/memgraph" + "github.com/vcscsvcscs/GenerationsHeritage/apps/db-adapter/pkg/api" +) + +func (srv *server) CreateAdminRelationship(c *gin.Context, id1 int, id2 int, params api.CreateAdminRelationshipParams) { + session := srv.db.NewSession(c.Request.Context(), neo4j.SessionConfig{}) + defer closeSession(c.Request.Context(), session, srv.dbOpTimeout) + + actx, aCancel := context.WithTimeout(c.Request.Context(), srv.dbOpTimeout) + defer aCancel() + if err := auth.CouldManagePerson(actx, session, id1, id2, params.XUserID); err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"msg": fmt.Sprint("User does not have permissions to manage this person with error:", err.Error())}) + + return + } + + qctx, qCancel := context.WithTimeout(c.Request.Context(), srv.dbOpTimeout) + defer qCancel() + + res, err := session.ExecuteWrite(qctx, memgraph.CreateAdminRelationship(qctx, id1, id2)) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()}) + + return + } + + c.JSON(http.StatusOK, res) +} + +func (srv *server) DeleteAdminRelationship(c *gin.Context, id1 int, id2 int, params api.DeleteAdminRelationshipParams) { + session := srv.db.NewSession(c.Request.Context(), neo4j.SessionConfig{}) + defer closeSession(c.Request.Context(), session, srv.dbOpTimeout) + + actx, aCancel := context.WithTimeout(c.Request.Context(), srv.dbOpTimeout) + defer aCancel() + if err := auth.CouldManagePerson(actx, session, id1, id2, params.XUserID); err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"msg": fmt.Sprint("User does not have permissions to manage this person with error:", err.Error())}) + + return + } + + qctx, qCancel := context.WithTimeout(c.Request.Context(), srv.dbOpTimeout) + defer qCancel() + + _, err := session.ExecuteWrite(qctx, memgraph.DeleteAdminRelationship(qctx, id1, id2)) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()}) + + return + } + + c.JSON(http.StatusOK, gin.H{"msg": "admin relationship was deleted"}) +} + +func (srv *server) GetAdminRelationship(c *gin.Context, id1 int, id2 int, params api.GetAdminRelationshipParams) { + session := srv.db.NewSession(c.Request.Context(), neo4j.SessionConfig{}) + defer closeSession(c.Request.Context(), session, srv.dbOpTimeout) + + actx, aCancel := context.WithTimeout(c.Request.Context(), srv.dbOpTimeout) + defer aCancel() + if err := auth.CouldSeePersonsProfile(actx, session, id1, params.XUserID); err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"msg": fmt.Sprint("User does not have permissions to see this person", err.Error())}) + + return + } + + qctx, qCancel := context.WithTimeout(c.Request.Context(), srv.dbOpTimeout) + defer qCancel() + + res, err := session.ExecuteRead(qctx, memgraph.GetAdminRelationship(qctx, id1, id2)) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()}) + + return + } + + c.JSON(http.StatusOK, res) +} + +func (srv *server) GetProfileAdmins(c *gin.Context, id int, params api.GetProfileAdminsParams) { + session := srv.db.NewSession(c.Request.Context(), neo4j.SessionConfig{}) + defer closeSession(c.Request.Context(), session, srv.dbOpTimeout) + + actx, aCancel := context.WithTimeout(c.Request.Context(), srv.dbOpTimeout) + defer aCancel() + if err := auth.CouldSeePersonsProfile(actx, session, id, params.XUserID); err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"msg": fmt.Sprint("User does not have permissions to see this person", err.Error())}) + + return + } + + qctx, qCancel := context.WithTimeout(c.Request.Context(), srv.dbOpTimeout) + defer qCancel() + + res, err := session.ExecuteRead(qctx, memgraph.GetProfileAdmins(qctx, id)) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()}) + + return + } + + c.JSON(http.StatusOK, res) +} + +func (srv *server) GetManagedProfiles(c *gin.Context, params api.GetManagedProfilesParams) { + session := srv.db.NewSession(c.Request.Context(), neo4j.SessionConfig{}) + defer closeSession(c.Request.Context(), session, srv.dbOpTimeout) + + qctx, qCancel := context.WithTimeout(c.Request.Context(), srv.dbOpTimeout) + defer qCancel() + + res, err := session.ExecuteRead(qctx, memgraph.GetManagedProfiles(qctx, id)) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()}) + + return + } + + c.JSON(http.StatusOK, res) +} diff --git a/apps/db-adapter/internal/api/auth/admin_operations.go b/apps/db-adapter/internal/api/auth/admin_operations.go new file mode 100644 index 0000000..481090c --- /dev/null +++ b/apps/db-adapter/internal/api/auth/admin_operations.go @@ -0,0 +1,27 @@ +package auth + +import ( + "context" + + "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/vcscsvcscs/GenerationsHeritage/apps/db-adapter/internal/memgraph" +) + +// This function checks if the user has permission to manage another user's profile, it returns an error if the user does not have permission. +func CouldManagePerson(ctx context.Context, session neo4j.SessionWithContext, userId, adminId, XUserID int) error { + if adminId == XUserID { + return nil + } + + return CouldManagePersonUnknownAdmin(ctx, session, userId, XUserID) +} + +// This function checks if the user has permission to manage another user's profile, it returns an error if the user does not have permission. +func CouldManagePersonUnknownAdmin(ctx context.Context, session neo4j.SessionWithContext, userId, XUserID int) error { + if userId == XUserID { + return nil + } + + _, err := session.ExecuteRead(ctx, memgraph.GetAdminRelationship(ctx, userId, XUserID), nil) + return err +} diff --git a/apps/db-adapter/internal/api/auth/read_operations.go b/apps/db-adapter/internal/api/auth/read_operations.go new file mode 100644 index 0000000..a150a4c --- /dev/null +++ b/apps/db-adapter/internal/api/auth/read_operations.go @@ -0,0 +1,14 @@ +package auth + +import ( + "context" + + "github.com/neo4j/neo4j-go-driver/v5/neo4j" +) + +func CouldSeePersonsProfile(ctx context.Context, session neo4j.SessionWithContext, userId, XUserID int) error { + if CouldManagePersonUnknownAdmin(ctx, session, userId, XUserID) == nil { + return nil + } + +} diff --git a/apps/db-adapter/internal/api/authorization_by_id.go b/apps/db-adapter/internal/api/authorization_by_id.go deleted file mode 100644 index 2766ee0..0000000 --- a/apps/db-adapter/internal/api/authorization_by_id.go +++ /dev/null @@ -1,45 +0,0 @@ -package api - -import ( - "context" - - "github.com/neo4j/neo4j-go-driver/v5/neo4j" - "github.com/vcscsvcscs/GenerationsHeritage/apps/db-adapter/internal/memgraph" -) - -type accessMode int - -const ( - accessModeNone accessMode = iota - accessModeRead - accessModeWrite -) - -func userWithIdHasAccessToGivenPerson(ctx context.Context, session neo4j.SessionWithContext, userId, personId int) accessMode { - resPerson, err := session.ExecuteRead(ctx, memgraph.GetPersonById(ctx, userId)) - if err != nil { - return accessModeNone - } - - resPersonMap, ok := resPerson.(map[string]any) - if !ok { - return accessModeNone - } - - if resPersonMap["id"] == userId { - return accessModeWrite - } - - AllowAdminAccess, ok := resPersonMap["allow_admin_access"].([]map[string]any) - if !ok { - return accessModeNone - } - - for _, admin := range AllowAdminAccess { - if admin["id"].(int) == userId { - return accessModeWrite - } - } - - return accessModeNone -} diff --git a/apps/db-adapter/internal/api/person.go b/apps/db-adapter/internal/api/person.go index d4fc7d5..54d0139 100644 --- a/apps/db-adapter/internal/api/person.go +++ b/apps/db-adapter/internal/api/person.go @@ -2,10 +2,12 @@ package api import ( "context" + "fmt" "net/http" "github.com/gin-gonic/gin" "github.com/neo4j/neo4j-go-driver/v5/neo4j" + "github.com/vcscsvcscs/GenerationsHeritage/apps/db-adapter/internal/api/auth" "github.com/vcscsvcscs/GenerationsHeritage/apps/db-adapter/internal/memgraph" "github.com/vcscsvcscs/GenerationsHeritage/apps/db-adapter/pkg/api" ) @@ -18,29 +20,57 @@ func (srv *server) CreatePerson(c *gin.Context, params api.CreatePersonParams) { return } - adminList := []struct { - Id *int "json:\"id,omitempty\"" - Name *string "json:\"name,omitempty\"" - }{ - {Id: ¶ms.XUserID, Name: ¶ms.XUserName}, - } - person.AllowAdminAccess = &adminList - - ctx, cancel := context.WithTimeout(context.Background(), srv.dbOpTimeout) - defer cancel() - session := srv.db.NewSession(ctx, neo4j.SessionConfig{}) + session := srv.db.NewSession(c.Request.Context(), neo4j.SessionConfig{}) defer closeSession(c.Request.Context(), session, srv.dbOpTimeout) + trs, err := session.BeginTransaction(c.Request.Context()) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()}) + + return + } + defer func() { + trs.Commit(c.Request.Context()) + trs.Close(c.Request.Context()) + }() + qctx, qCancel := context.WithTimeout(context.Background(), srv.dbOpTimeout) defer qCancel() - res, err := session.ExecuteRead(qctx, memgraph.CreatePerson(qctx, person)) + res, err := trs.Run(qctx, memgraph.CreatePersonCypherQuery, map[string]any{ + "Person": *person, + }) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()}) return } - c.JSON(http.StatusOK, res) + singleRes, err := res.Single(qctx) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()}) + + return + } + personId, ok := singleRes.Get("id") + if !ok { + c.JSON(http.StatusInternalServerError, gin.H{"msg": "Person ID not found in response"}) + + return + } + + actx, acancel := context.WithTimeout(context.Background(), srv.dbOpTimeout) + defer acancel() + _, aErr := trs.Run(actx, memgraph.CreateAdminRelationshipCypherQuery, map[string]any{ + "id2": personId.(int), + "id1": params.XUserID, + }) + if aErr != nil { + c.JSON(http.StatusInternalServerError, gin.H{"msg": aErr.Error()}) + + return + } + + c.JSON(http.StatusOK, singleRes.AsMap()) } func (srv *server) GetPersonById(c *gin.Context, id int, params api.GetPersonByIdParams) { @@ -51,8 +81,8 @@ func (srv *server) GetPersonById(c *gin.Context, id int, params api.GetPersonByI actx, acancel := context.WithTimeout(context.Background(), srv.dbOpTimeout) defer acancel() - if userWithIdHasAccessToGivenPerson(actx, session, params.XUserID, id) == accessModeNone { - c.JSON(http.StatusUnauthorized, gin.H{"msg": "User does not have access to this person"}) + if err := auth.CouldSeePersonsProfile(actx, session, id, params.XUserID); err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"msg": fmt.Sprint("User does not have access to this person", err.Error())}) return } @@ -77,8 +107,8 @@ func (srv *server) SoftDeletePerson(c *gin.Context, id int, params api.SoftDelet actx, acancel := context.WithTimeout(context.Background(), srv.dbOpTimeout) defer acancel() - if userWithIdHasAccessToGivenPerson(actx, session, params.XUserID, id) != accessModeWrite { - c.JSON(http.StatusUnauthorized, gin.H{"msg": "User does not have access to this person"}) + if err := auth.CouldManagePersonUnknownAdmin(actx, session, id, params.XUserID); err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"msg": fmt.Sprint("User does not have access to this person", err.Error())}) return } @@ -108,8 +138,8 @@ func (srv *server) UpdatePerson(c *gin.Context, id int, params api.UpdatePersonP session := srv.db.NewSession(actx, neo4j.SessionConfig{}) defer closeSession(c.Request.Context(), session, srv.dbOpTimeout) - if userWithIdHasAccessToGivenPerson(actx, session, params.XUserID, id) != accessModeWrite { - c.JSON(http.StatusUnauthorized, gin.H{"msg": "User does not have access to this person"}) + if err := auth.CouldManagePersonUnknownAdmin(actx, session, id, params.XUserID); err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"msg": fmt.Sprint("User does not have access to this person", err.Error())}) return } @@ -134,8 +164,8 @@ func (srv *server) HardDeletePerson(c *gin.Context, id int, params api.HardDelet actx, acancel := context.WithTimeout(context.Background(), srv.dbOpTimeout) defer acancel() - if userWithIdHasAccessToGivenPerson(actx, session, params.XUserID, id) != accessModeWrite { - c.JSON(http.StatusUnauthorized, gin.H{"msg": "User does not have access to this person"}) + if err := auth.CouldManagePersonUnknownAdmin(actx, session, id, params.XUserID); err != nil { + c.JSON(http.StatusUnauthorized, gin.H{"msg": fmt.Sprint("User does not have access to this person", err.Error())}) return } diff --git a/apps/db-adapter/internal/api/person_and_relationship.go b/apps/db-adapter/internal/api/person_and_relationship.go index 6441f4e..88ddaf8 100644 --- a/apps/db-adapter/internal/api/person_and_relationship.go +++ b/apps/db-adapter/internal/api/person_and_relationship.go @@ -27,19 +27,13 @@ func (srv *server) CreatePersonAndRelationship(c *gin.Context, id int, params ap qctx, qCancel := context.WithTimeout(ctx, srv.dbOpTimeout) defer qCancel() - res, err := session.ExecuteRead(qctx, memgraph.CreatePerson(qctx, &api.PersonProperties{ + res, err := session.ExecuteWrite(qctx, memgraph.CreatePerson(qctx, &api.PersonProperties{ FirstName: &requestBody.Person.FirstName, LastName: &requestBody.Person.LastName, Born: &requestBody.Person.Born, MothersFirstName: &requestBody.Person.MothersFirstName, MothersLastName: &requestBody.Person.MothersLastName, Limit: &requestBody.Person.Limit, - AllowAdminAccess: &[]struct { - Id *int "json:\"id,omitempty\"" - Name *string "json:\"name,omitempty\"" - }{ - {Id: ¶ms.XUserID}, - }, })) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()}) diff --git a/apps/db-adapter/internal/api/person_google.go b/apps/db-adapter/internal/api/person_google.go index e66d87a..22c0d2e 100644 --- a/apps/db-adapter/internal/api/person_google.go +++ b/apps/db-adapter/internal/api/person_google.go @@ -47,7 +47,7 @@ func (srv *server) CreatePersonByGoogleIdAndInviteCode(c *gin.Context, googleId qctx, qCancel := context.WithTimeout(context.Background(), srv.dbOpTimeout) defer qCancel() - res, err := session.ExecuteRead(qctx, memgraph.UpdatePersonByInviteCode(qctx, person.InviteCode, person.Props)) + res, err := session.ExecuteWrite(qctx, memgraph.UpdatePersonByInviteCode(qctx, person.InviteCode, person.Props)) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()}) @@ -72,7 +72,7 @@ func (srv *server) CreatePersonByGoogleId(c *gin.Context, googleId string) { qctx, qCancel := context.WithTimeout(context.Background(), srv.dbOpTimeout) defer qCancel() - res, err := session.ExecuteRead(qctx, memgraph.CreatePerson(qctx, person)) + res, err := session.ExecuteWrite(qctx, memgraph.CreatePerson(qctx, person)) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()}) diff --git a/apps/db-adapter/internal/memgraph/admin.go b/apps/db-adapter/internal/memgraph/admin.go index e247c11..300767f 100644 --- a/apps/db-adapter/internal/memgraph/admin.go +++ b/apps/db-adapter/internal/memgraph/admin.go @@ -1 +1,77 @@ package memgraph + +import ( + "context" + "fmt" + + "github.com/neo4j/neo4j-go-driver/v5/neo4j" +) + +func CreateAdminRelationship(ctx context.Context, userId int, adminId int) neo4j.ManagedTransactionWork { + return func(tx neo4j.ManagedTransaction) (any, error) { + result, err := tx.Run(ctx, CreateAdminRelationshipCypherQuery, map[string]any{ + "id1": adminId, + "id2": userId, + }) + if err != nil { + return nil, err + } + + record, err := result.Single(ctx) + if err != nil { + return nil, err + } + + return record.AsMap(), nil + } +} + +func DeleteAdminRelationship(ctx context.Context, userId int, adminId int) neo4j.ManagedTransactionWork { + return func(tx neo4j.ManagedTransaction) (any, error) { + result, err := tx.Run(ctx, DeleteAdminRelationshipCypherQuery, map[string]any{ + "id1": adminId, + "id2": userId, + }) + if err != nil { + return nil, err + } + + if result.Peek(ctx) { + return nil, fmt.Errorf("there was a returned value, when deleting admin but there should be none") + } + + return nil, nil + } +} + +func GetAdminRelationship(ctx context.Context, userId int, adminId int) neo4j.ManagedTransactionWork { + return func(tx neo4j.ManagedTransaction) (any, error) { + result, err := tx.Run(ctx, GetAdminRelationshipCypherQuery, map[string]any{ + "id1": adminId, + "id2": userId, + }) + if err != nil { + return nil, err + } + + record, err := result.Single(ctx) + if err != nil { + return nil, err + } + + return record.AsMap(), nil + } +} + +func GetProfileAdmins(ctx context.Context, userId int) neo4j.ManagedTransactionWork { + return func(tx neo4j.ManagedTransaction) (any, error) { + result, err := tx.Run(ctx, GetProfileAdminsCypherQuery, map[string]any{ + "id": userId, + }) + if err != nil { + return nil, err + } + + return result.Collect(ctx) + } +} diff --git a/apps/db-adapter/internal/memgraph/queries.go b/apps/db-adapter/internal/memgraph/queries.go index ed7830a..2ecd2ba 100644 --- a/apps/db-adapter/internal/memgraph/queries.go +++ b/apps/db-adapter/internal/memgraph/queries.go @@ -86,3 +86,23 @@ var DeleteRelationshipCypherQuery string // //go:embed queries/get_family_tree_by_id.cypher var GetFamilyTreeByIdCypherQuery string + +// Requires id1, id2 parameter. +// +//go:embed queries/create_admin_relationship.cypher +var CreateAdminRelationshipCypherQuery string + +// Requires id1, id2 parameter. +// +//go:embed queries/delete_admin_relationship.cypher +var DeleteAdminRelationshipCypherQuery string + +// Requires id1, id2 parameter. +// +//go:embed queries/get_admin_relationship.cypher +var GetAdminRelationshipCypherQuery string + +// Requires id parameter. +// +//go:embed queries/get_profile_admins.cypher +var GetProfileAdminsCypherQuery string diff --git a/apps/db-adapter/internal/memgraph/queries/create_admin_relationship.cypher b/apps/db-adapter/internal/memgraph/queries/create_admin_relationship.cypher new file mode 100644 index 0000000..4cb5d0c --- /dev/null +++ b/apps/db-adapter/internal/memgraph/queries/create_admin_relationship.cypher @@ -0,0 +1,5 @@ +MATCH (a:Person), (b:Person) +WHERE id(a) = $id1 AND id(b) = $id2 AND $id1 != $id2 +MERGE (a)-[r1:Admin]->(b) +ON CREATE SET r1 = {added : timestamp()} +RETURN r1 as relationship; \ No newline at end of file diff --git a/apps/db-adapter/internal/memgraph/queries/delete_admin_relationship.cypher b/apps/db-adapter/internal/memgraph/queries/delete_admin_relationship.cypher new file mode 100644 index 0000000..a894b77 --- /dev/null +++ b/apps/db-adapter/internal/memgraph/queries/delete_admin_relationship.cypher @@ -0,0 +1,3 @@ +MATCH (a)-[r1:Admin]->(b) +WHERE id(a) = $id1 AND id(b) = $id2 AND $id1 != $id2 +DELETE r1; \ No newline at end of file diff --git a/apps/db-adapter/internal/memgraph/queries/get_admin_relationship.cypher b/apps/db-adapter/internal/memgraph/queries/get_admin_relationship.cypher new file mode 100644 index 0000000..ed84cee --- /dev/null +++ b/apps/db-adapter/internal/memgraph/queries/get_admin_relationship.cypher @@ -0,0 +1,3 @@ +MATCH (a)-[r1:Admin]->(b) +WHERE id(a) = $id1 AND id(b) = $id2 AND $id1 != $id2 +RETURN r1 as relationship; \ No newline at end of file diff --git a/apps/db-adapter/internal/memgraph/queries/get_profile_admins.cypher b/apps/db-adapter/internal/memgraph/queries/get_profile_admins.cypher new file mode 100644 index 0000000..1da33fe --- /dev/null +++ b/apps/db-adapter/internal/memgraph/queries/get_profile_admins.cypher @@ -0,0 +1,3 @@ +MATCH (a)-[r1:Admin]->(b) +WHERE id(b) = $id +RETURN collect(r1) as adminRelationship, collect({id: id(a), first_name: a.first_name, last_name: a.last_name}) as admins; \ No newline at end of file diff --git a/apps/db-adapter/pkg/api/api.gen.go b/apps/db-adapter/pkg/api/api.gen.go index 403a5c9..8dcfa35 100644 --- a/apps/db-adapter/pkg/api/api.gen.go +++ b/apps/db-adapter/pkg/api/api.gen.go @@ -28,6 +28,15 @@ const ( CreateRelationshipJSONBodyTypeSpouse CreateRelationshipJSONBodyType = "spouse" ) +// Admin defines model for Admin. +type Admin struct { + End *string `json:"end,omitempty"` + Id *int `json:"id,omitempty"` + Label *string `json:"label,omitempty"` + Properties *map[string]interface{} `json:"properties,omitempty"` + Start *string `json:"start,omitempty"` +} + // FamilyRelationship defines model for FamilyRelationship. type FamilyRelationship struct { From *openapi_types.Date `json:"from"` @@ -65,14 +74,15 @@ type LikesProperties struct { // OptimizedPersonNode defines model for OptimizedPersonNode. type OptimizedPersonNode struct { - Born *openapi_types.Date `json:"born,omitempty"` - Died *openapi_types.Date `json:"died"` - FirstName *string `json:"first_name,omitempty"` - Id *int `json:"id,omitempty"` - Labels *[]string `json:"labels,omitempty"` - LastName *string `json:"last_name,omitempty"` - MiddleName *string `json:"middle_name,omitempty"` - Type *string `json:"type"` + Born *openapi_types.Date `json:"born,omitempty"` + Died *openapi_types.Date `json:"died"` + FirstName *string `json:"first_name,omitempty"` + Id *int `json:"id,omitempty"` + Labels *[]string `json:"labels,omitempty"` + LastName *string `json:"last_name,omitempty"` + MiddleName *string `json:"middle_name,omitempty"` + ProfilePicture *string `json:"profile_picture"` + Type *string `json:"type"` } // Person defines model for Person. @@ -85,13 +95,9 @@ type Person struct { // PersonProperties defines model for PersonProperties. type PersonProperties struct { - Aliases *[]string `json:"aliases"` - Allergies *[]string `json:"allergies"` - AllowAdminAccess *[]struct { - Id *int `json:"id,omitempty"` - Name *string `json:"name,omitempty"` - } `json:"allow_admin_access"` - Audios *[]struct { + Aliases *[]string `json:"aliases"` + Allergies *[]string `json:"allergies"` + Audios *[]struct { Date *openapi_types.Date `json:"date,omitempty"` Description *string `json:"description,omitempty"` Name *string `json:"name,omitempty"` @@ -232,6 +238,31 @@ type Relationship struct { Type *string `json:"type"` } +// GetProfileAdminsParams defines parameters for GetProfileAdmins. +type GetProfileAdminsParams struct { + XUserID int `json:"X-User-ID"` +} + +// DeleteAdminRelationshipParams defines parameters for DeleteAdminRelationship. +type DeleteAdminRelationshipParams struct { + XUserID int `json:"X-User-ID"` +} + +// GetAdminRelationshipParams defines parameters for GetAdminRelationship. +type GetAdminRelationshipParams struct { + XUserID int `json:"X-User-ID"` +} + +// CreateAdminRelationshipParams defines parameters for CreateAdminRelationship. +type CreateAdminRelationshipParams struct { + XUserID int `json:"X-User-ID"` +} + +// GetManagedProfilesParams defines parameters for GetManagedProfiles. +type GetManagedProfilesParams struct { + XUserID int `json:"X-User-ID"` +} + // CreatePersonParams defines parameters for CreatePerson. type CreatePersonParams struct { XUserID int `json:"X-User-ID"` @@ -365,9 +396,24 @@ type CreateRelationshipJSONRequestBody CreateRelationshipJSONBody // ServerInterface represents all server handlers. type ServerInterface interface { + // Get profile Admins + // (GET /admin/{id1}) + GetProfileAdmins(c *gin.Context, id1 int, params GetProfileAdminsParams) + // Delete admin relationship between two persons + // (DELETE /admin/{id1}/{id2}) + DeleteAdminRelationship(c *gin.Context, id1 int, id2 int, params DeleteAdminRelationshipParams) + // Get admin relationship between two persons + // (GET /admin/{id1}/{id2}) + GetAdminRelationship(c *gin.Context, id1 int, id2 int, params GetAdminRelationshipParams) + // Create admin relationship between two persons + // (POST /admin/{id1}/{id2}) + CreateAdminRelationship(c *gin.Context, id1 int, id2 int, params CreateAdminRelationshipParams) // Check the health of the server // (GET /health) HealthCheck(c *gin.Context) + // Get managed profiles + // (GET /managed_profiles) + GetManagedProfiles(c *gin.Context, params GetManagedProfilesParams) // Create a new person // (POST /person) CreatePerson(c *gin.Context, params CreatePersonParams) @@ -433,6 +479,237 @@ type ServerInterfaceWrapper struct { type MiddlewareFunc func(c *gin.Context) +// GetProfileAdmins operation middleware +func (siw *ServerInterfaceWrapper) GetProfileAdmins(c *gin.Context) { + + var err error + + // ------------- Path parameter "id1" ------------- + var id1 int + + err = runtime.BindStyledParameterWithOptions("simple", "id1", c.Param("id1"), &id1, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id1: %w", err), http.StatusBadRequest) + return + } + + // Parameter object where we will unmarshal all parameters from the context + var params GetProfileAdminsParams + + headers := c.Request.Header + + // ------------- Required header parameter "X-User-ID" ------------- + if valueList, found := headers[http.CanonicalHeaderKey("X-User-ID")]; found { + var XUserID int + n := len(valueList) + if n != 1 { + siw.ErrorHandler(c, fmt.Errorf("Expected one value for X-User-ID, got %d", n), http.StatusBadRequest) + return + } + + err = runtime.BindStyledParameterWithOptions("simple", "X-User-ID", valueList[0], &XUserID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter X-User-ID: %w", err), http.StatusBadRequest) + return + } + + params.XUserID = XUserID + + } else { + siw.ErrorHandler(c, fmt.Errorf("Header parameter X-User-ID is required, but not found"), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.GetProfileAdmins(c, id1, params) +} + +// DeleteAdminRelationship operation middleware +func (siw *ServerInterfaceWrapper) DeleteAdminRelationship(c *gin.Context) { + + var err error + + // ------------- Path parameter "id1" ------------- + var id1 int + + err = runtime.BindStyledParameterWithOptions("simple", "id1", c.Param("id1"), &id1, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id1: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "id2" ------------- + var id2 int + + err = runtime.BindStyledParameterWithOptions("simple", "id2", c.Param("id2"), &id2, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id2: %w", err), http.StatusBadRequest) + return + } + + // Parameter object where we will unmarshal all parameters from the context + var params DeleteAdminRelationshipParams + + headers := c.Request.Header + + // ------------- Required header parameter "X-User-ID" ------------- + if valueList, found := headers[http.CanonicalHeaderKey("X-User-ID")]; found { + var XUserID int + n := len(valueList) + if n != 1 { + siw.ErrorHandler(c, fmt.Errorf("Expected one value for X-User-ID, got %d", n), http.StatusBadRequest) + return + } + + err = runtime.BindStyledParameterWithOptions("simple", "X-User-ID", valueList[0], &XUserID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter X-User-ID: %w", err), http.StatusBadRequest) + return + } + + params.XUserID = XUserID + + } else { + siw.ErrorHandler(c, fmt.Errorf("Header parameter X-User-ID is required, but not found"), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.DeleteAdminRelationship(c, id1, id2, params) +} + +// GetAdminRelationship operation middleware +func (siw *ServerInterfaceWrapper) GetAdminRelationship(c *gin.Context) { + + var err error + + // ------------- Path parameter "id1" ------------- + var id1 int + + err = runtime.BindStyledParameterWithOptions("simple", "id1", c.Param("id1"), &id1, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id1: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "id2" ------------- + var id2 int + + err = runtime.BindStyledParameterWithOptions("simple", "id2", c.Param("id2"), &id2, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id2: %w", err), http.StatusBadRequest) + return + } + + // Parameter object where we will unmarshal all parameters from the context + var params GetAdminRelationshipParams + + headers := c.Request.Header + + // ------------- Required header parameter "X-User-ID" ------------- + if valueList, found := headers[http.CanonicalHeaderKey("X-User-ID")]; found { + var XUserID int + n := len(valueList) + if n != 1 { + siw.ErrorHandler(c, fmt.Errorf("Expected one value for X-User-ID, got %d", n), http.StatusBadRequest) + return + } + + err = runtime.BindStyledParameterWithOptions("simple", "X-User-ID", valueList[0], &XUserID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter X-User-ID: %w", err), http.StatusBadRequest) + return + } + + params.XUserID = XUserID + + } else { + siw.ErrorHandler(c, fmt.Errorf("Header parameter X-User-ID is required, but not found"), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.GetAdminRelationship(c, id1, id2, params) +} + +// CreateAdminRelationship operation middleware +func (siw *ServerInterfaceWrapper) CreateAdminRelationship(c *gin.Context) { + + var err error + + // ------------- Path parameter "id1" ------------- + var id1 int + + err = runtime.BindStyledParameterWithOptions("simple", "id1", c.Param("id1"), &id1, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id1: %w", err), http.StatusBadRequest) + return + } + + // ------------- Path parameter "id2" ------------- + var id2 int + + err = runtime.BindStyledParameterWithOptions("simple", "id2", c.Param("id2"), &id2, runtime.BindStyledParameterOptions{Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id2: %w", err), http.StatusBadRequest) + return + } + + // Parameter object where we will unmarshal all parameters from the context + var params CreateAdminRelationshipParams + + headers := c.Request.Header + + // ------------- Required header parameter "X-User-ID" ------------- + if valueList, found := headers[http.CanonicalHeaderKey("X-User-ID")]; found { + var XUserID int + n := len(valueList) + if n != 1 { + siw.ErrorHandler(c, fmt.Errorf("Expected one value for X-User-ID, got %d", n), http.StatusBadRequest) + return + } + + err = runtime.BindStyledParameterWithOptions("simple", "X-User-ID", valueList[0], &XUserID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter X-User-ID: %w", err), http.StatusBadRequest) + return + } + + params.XUserID = XUserID + + } else { + siw.ErrorHandler(c, fmt.Errorf("Header parameter X-User-ID is required, but not found"), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.CreateAdminRelationship(c, id1, id2, params) +} + // HealthCheck operation middleware func (siw *ServerInterfaceWrapper) HealthCheck(c *gin.Context) { @@ -446,6 +723,48 @@ func (siw *ServerInterfaceWrapper) HealthCheck(c *gin.Context) { siw.Handler.HealthCheck(c) } +// GetManagedProfiles operation middleware +func (siw *ServerInterfaceWrapper) GetManagedProfiles(c *gin.Context) { + + var err error + + // Parameter object where we will unmarshal all parameters from the context + var params GetManagedProfilesParams + + headers := c.Request.Header + + // ------------- Required header parameter "X-User-ID" ------------- + if valueList, found := headers[http.CanonicalHeaderKey("X-User-ID")]; found { + var XUserID int + n := len(valueList) + if n != 1 { + siw.ErrorHandler(c, fmt.Errorf("Expected one value for X-User-ID, got %d", n), http.StatusBadRequest) + return + } + + err = runtime.BindStyledParameterWithOptions("simple", "X-User-ID", valueList[0], &XUserID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter X-User-ID: %w", err), http.StatusBadRequest) + return + } + + params.XUserID = XUserID + + } else { + siw.ErrorHandler(c, fmt.Errorf("Header parameter X-User-ID is required, but not found"), http.StatusBadRequest) + return + } + + for _, middleware := range siw.HandlerMiddlewares { + middleware(c) + if c.IsAborted() { + return + } + } + + siw.Handler.GetManagedProfiles(c, params) +} + // CreatePerson operation middleware func (siw *ServerInterfaceWrapper) CreatePerson(c *gin.Context) { @@ -1311,7 +1630,12 @@ func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options ErrorHandler: errorHandler, } + router.GET(options.BaseURL+"/admin/:id1", wrapper.GetProfileAdmins) + router.DELETE(options.BaseURL+"/admin/:id1/:id2", wrapper.DeleteAdminRelationship) + router.GET(options.BaseURL+"/admin/:id1/:id2", wrapper.GetAdminRelationship) + router.POST(options.BaseURL+"/admin/:id1/:id2", wrapper.CreateAdminRelationship) router.GET(options.BaseURL+"/health", wrapper.HealthCheck) + router.GET(options.BaseURL+"/managed_profiles", wrapper.GetManagedProfiles) router.POST(options.BaseURL+"/person", wrapper.CreatePerson) router.GET(options.BaseURL+"/person/google/:google_id", wrapper.GetPersonByGoogleId) router.PATCH(options.BaseURL+"/person/google/:google_id", wrapper.CreatePersonByGoogleIdAndInviteCode)