@@ -46,13 +46,32 @@ type UsersJwtResponse struct {
4646// @Security BearerAuth
4747// @Router /users [get]
4848func GetUsers (w http.ResponseWriter , r * http.Request ) {
49- users , err := db .GetAllUsers (r .Context ())
50- if err != nil {
51- httpx .WriteError (w , http .StatusInternalServerError , "Failed to get users: " + err .Error ())
49+ user := httpx .UserFromRequest (r )
50+
51+ // Admin sees all users
52+ if user .Role != nil && user .Role .Role == obj .RoleAdmin {
53+ users , err := db .GetAllUsers (r .Context ())
54+ if err != nil {
55+ httpx .WriteError (w , http .StatusInternalServerError , "Failed to get users: " + err .Error ())
56+ return
57+ }
58+ httpx .WriteJSON (w , http .StatusOK , users )
5259 return
5360 }
5461
55- httpx .WriteJSON (w , http .StatusOK , users )
62+ // Head/staff sees members of their institution
63+ if user .Role != nil && (user .Role .Role == obj .RoleHead || user .Role .Role == obj .RoleStaff ) && user .Role .Institution != nil {
64+ members , err := db .GetInstitutionMembers (r .Context (), user .Role .Institution .ID , user .ID )
65+ if err != nil {
66+ httpx .WriteError (w , http .StatusInternalServerError , "Failed to get users: " + err .Error ())
67+ return
68+ }
69+ httpx .WriteJSON (w , http .StatusOK , members )
70+ return
71+ }
72+
73+ // Everyone else (individual, participant) gets 403
74+ httpx .WriteAppError (w , obj .ErrForbidden ("only admins or institution heads/staff can list users" ))
5675}
5776
5877// GetCurrentUser godoc
@@ -159,15 +178,23 @@ func UpdateUserLanguage(w http.ResponseWriter, r *http.Request) {
159178// @Security BearerAuth
160179// @Router /users/{id} [get]
161180func GetUserByID (w http.ResponseWriter , r * http.Request ) {
162- userID , err := httpx .PathParamUUID (r , "id" )
181+ currentUser := httpx .UserFromRequest (r )
182+
183+ targetID , err := httpx .PathParamUUID (r , "id" )
163184 if err != nil {
164185 httpx .WriteError (w , http .StatusBadRequest , "Invalid user ID" )
165186 return
166187 }
167188
168- log .Debug ("getting user by ID" , "user_id" , userID )
189+ log .Debug ("getting user by ID" , "user_id" , targetID , "requested_by" , currentUser . ID )
169190
170- user , err := db .GetUserByID (r .Context (), userID )
191+ // Permission check: own profile, admin, or head/staff for org members
192+ if err := db .CanReadUser (r .Context (), currentUser .ID , targetID ); err != nil {
193+ httpx .WriteError (w , http .StatusForbidden , "Not authorized to read this user" )
194+ return
195+ }
196+
197+ user , err := db .GetUserByID (r .Context (), targetID )
171198 if err != nil {
172199 httpx .WriteError (w , http .StatusNotFound , "User not found" )
173200 return
@@ -438,6 +465,8 @@ func DeleteUser(w http.ResponseWriter, r *http.Request) {
438465 status = http .StatusForbidden
439466 case obj .ErrCodeUnauthorized :
440467 status = http .StatusUnauthorized
468+ case obj .ErrCodeLastHead :
469+ status = http .StatusConflict
441470 }
442471 httpx .WriteError (w , status , appErr .Error ())
443472 } else {
0 commit comments