code.gitea.io/gitea@v1.21.7/routers/api/v1/org/org.go (about) 1 // Copyright 2015 The Gogs Authors. All rights reserved. 2 // Copyright 2018 The Gitea Authors. All rights reserved. 3 // SPDX-License-Identifier: MIT 4 5 package org 6 7 import ( 8 "net/http" 9 10 activities_model "code.gitea.io/gitea/models/activities" 11 "code.gitea.io/gitea/models/db" 12 "code.gitea.io/gitea/models/organization" 13 "code.gitea.io/gitea/models/perm" 14 user_model "code.gitea.io/gitea/models/user" 15 "code.gitea.io/gitea/modules/context" 16 api "code.gitea.io/gitea/modules/structs" 17 "code.gitea.io/gitea/modules/web" 18 "code.gitea.io/gitea/routers/api/v1/user" 19 "code.gitea.io/gitea/routers/api/v1/utils" 20 "code.gitea.io/gitea/services/convert" 21 "code.gitea.io/gitea/services/org" 22 ) 23 24 func listUserOrgs(ctx *context.APIContext, u *user_model.User) { 25 listOptions := utils.GetListOptions(ctx) 26 showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == u.ID) 27 28 opts := organization.FindOrgOptions{ 29 ListOptions: listOptions, 30 UserID: u.ID, 31 IncludePrivate: showPrivate, 32 } 33 orgs, err := organization.FindOrgs(opts) 34 if err != nil { 35 ctx.Error(http.StatusInternalServerError, "FindOrgs", err) 36 return 37 } 38 maxResults, err := organization.CountOrgs(opts) 39 if err != nil { 40 ctx.Error(http.StatusInternalServerError, "CountOrgs", err) 41 return 42 } 43 44 apiOrgs := make([]*api.Organization, len(orgs)) 45 for i := range orgs { 46 apiOrgs[i] = convert.ToOrganization(ctx, orgs[i]) 47 } 48 49 ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) 50 ctx.SetTotalCountHeader(maxResults) 51 ctx.JSON(http.StatusOK, &apiOrgs) 52 } 53 54 // ListMyOrgs list all my orgs 55 func ListMyOrgs(ctx *context.APIContext) { 56 // swagger:operation GET /user/orgs organization orgListCurrentUserOrgs 57 // --- 58 // summary: List the current user's organizations 59 // produces: 60 // - application/json 61 // parameters: 62 // - name: page 63 // in: query 64 // description: page number of results to return (1-based) 65 // type: integer 66 // - name: limit 67 // in: query 68 // description: page size of results 69 // type: integer 70 // responses: 71 // "200": 72 // "$ref": "#/responses/OrganizationList" 73 // "404": 74 // "$ref": "#/responses/notFound" 75 76 listUserOrgs(ctx, ctx.Doer) 77 } 78 79 // ListUserOrgs list user's orgs 80 func ListUserOrgs(ctx *context.APIContext) { 81 // swagger:operation GET /users/{username}/orgs organization orgListUserOrgs 82 // --- 83 // summary: List a user's organizations 84 // produces: 85 // - application/json 86 // parameters: 87 // - name: username 88 // in: path 89 // description: username of user 90 // type: string 91 // required: true 92 // - name: page 93 // in: query 94 // description: page number of results to return (1-based) 95 // type: integer 96 // - name: limit 97 // in: query 98 // description: page size of results 99 // type: integer 100 // responses: 101 // "200": 102 // "$ref": "#/responses/OrganizationList" 103 // "404": 104 // "$ref": "#/responses/notFound" 105 106 listUserOrgs(ctx, ctx.ContextUser) 107 } 108 109 // GetUserOrgsPermissions get user permissions in organization 110 func GetUserOrgsPermissions(ctx *context.APIContext) { 111 // swagger:operation GET /users/{username}/orgs/{org}/permissions organization orgGetUserPermissions 112 // --- 113 // summary: Get user permissions in organization 114 // produces: 115 // - application/json 116 // parameters: 117 // - name: username 118 // in: path 119 // description: username of user 120 // type: string 121 // required: true 122 // - name: org 123 // in: path 124 // description: name of the organization 125 // type: string 126 // required: true 127 // responses: 128 // "200": 129 // "$ref": "#/responses/OrganizationPermissions" 130 // "403": 131 // "$ref": "#/responses/forbidden" 132 // "404": 133 // "$ref": "#/responses/notFound" 134 135 var o *user_model.User 136 if o = user.GetUserByParamsName(ctx, ":org"); o == nil { 137 return 138 } 139 140 op := api.OrganizationPermissions{} 141 142 if !organization.HasOrgOrUserVisible(ctx, o, ctx.ContextUser) { 143 ctx.NotFound("HasOrgOrUserVisible", nil) 144 return 145 } 146 147 org := organization.OrgFromUser(o) 148 authorizeLevel, err := org.GetOrgUserMaxAuthorizeLevel(ctx.ContextUser.ID) 149 if err != nil { 150 ctx.Error(http.StatusInternalServerError, "GetOrgUserAuthorizeLevel", err) 151 return 152 } 153 154 if authorizeLevel > perm.AccessModeNone { 155 op.CanRead = true 156 } 157 if authorizeLevel > perm.AccessModeRead { 158 op.CanWrite = true 159 } 160 if authorizeLevel > perm.AccessModeWrite { 161 op.IsAdmin = true 162 } 163 if authorizeLevel > perm.AccessModeAdmin { 164 op.IsOwner = true 165 } 166 167 op.CanCreateRepository, err = org.CanCreateOrgRepo(ctx.ContextUser.ID) 168 if err != nil { 169 ctx.Error(http.StatusInternalServerError, "CanCreateOrgRepo", err) 170 return 171 } 172 173 ctx.JSON(http.StatusOK, op) 174 } 175 176 // GetAll return list of all public organizations 177 func GetAll(ctx *context.APIContext) { 178 // swagger:operation Get /orgs organization orgGetAll 179 // --- 180 // summary: Get list of organizations 181 // produces: 182 // - application/json 183 // parameters: 184 // - name: page 185 // in: query 186 // description: page number of results to return (1-based) 187 // type: integer 188 // - name: limit 189 // in: query 190 // description: page size of results 191 // type: integer 192 // responses: 193 // "200": 194 // "$ref": "#/responses/OrganizationList" 195 196 vMode := []api.VisibleType{api.VisibleTypePublic} 197 if ctx.IsSigned { 198 vMode = append(vMode, api.VisibleTypeLimited) 199 if ctx.Doer.IsAdmin { 200 vMode = append(vMode, api.VisibleTypePrivate) 201 } 202 } 203 204 listOptions := utils.GetListOptions(ctx) 205 206 publicOrgs, maxResults, err := user_model.SearchUsers(ctx, &user_model.SearchUserOptions{ 207 Actor: ctx.Doer, 208 ListOptions: listOptions, 209 Type: user_model.UserTypeOrganization, 210 OrderBy: db.SearchOrderByAlphabetically, 211 Visible: vMode, 212 }) 213 if err != nil { 214 ctx.Error(http.StatusInternalServerError, "SearchOrganizations", err) 215 return 216 } 217 orgs := make([]*api.Organization, len(publicOrgs)) 218 for i := range publicOrgs { 219 orgs[i] = convert.ToOrganization(ctx, organization.OrgFromUser(publicOrgs[i])) 220 } 221 222 ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) 223 ctx.SetTotalCountHeader(maxResults) 224 ctx.JSON(http.StatusOK, &orgs) 225 } 226 227 // Create api for create organization 228 func Create(ctx *context.APIContext) { 229 // swagger:operation POST /orgs organization orgCreate 230 // --- 231 // summary: Create an organization 232 // consumes: 233 // - application/json 234 // produces: 235 // - application/json 236 // parameters: 237 // - name: organization 238 // in: body 239 // required: true 240 // schema: { "$ref": "#/definitions/CreateOrgOption" } 241 // responses: 242 // "201": 243 // "$ref": "#/responses/Organization" 244 // "403": 245 // "$ref": "#/responses/forbidden" 246 // "422": 247 // "$ref": "#/responses/validationError" 248 form := web.GetForm(ctx).(*api.CreateOrgOption) 249 if !ctx.Doer.CanCreateOrganization() { 250 ctx.Error(http.StatusForbidden, "Create organization not allowed", nil) 251 return 252 } 253 254 visibility := api.VisibleTypePublic 255 if form.Visibility != "" { 256 visibility = api.VisibilityModes[form.Visibility] 257 } 258 259 org := &organization.Organization{ 260 Name: form.UserName, 261 FullName: form.FullName, 262 Email: form.Email, 263 Description: form.Description, 264 Website: form.Website, 265 Location: form.Location, 266 IsActive: true, 267 Type: user_model.UserTypeOrganization, 268 Visibility: visibility, 269 RepoAdminChangeTeamAccess: form.RepoAdminChangeTeamAccess, 270 } 271 if err := organization.CreateOrganization(org, ctx.Doer); err != nil { 272 if user_model.IsErrUserAlreadyExist(err) || 273 db.IsErrNameReserved(err) || 274 db.IsErrNameCharsNotAllowed(err) || 275 db.IsErrNamePatternNotAllowed(err) { 276 ctx.Error(http.StatusUnprocessableEntity, "", err) 277 } else { 278 ctx.Error(http.StatusInternalServerError, "CreateOrganization", err) 279 } 280 return 281 } 282 283 ctx.JSON(http.StatusCreated, convert.ToOrganization(ctx, org)) 284 } 285 286 // Get get an organization 287 func Get(ctx *context.APIContext) { 288 // swagger:operation GET /orgs/{org} organization orgGet 289 // --- 290 // summary: Get an organization 291 // produces: 292 // - application/json 293 // parameters: 294 // - name: org 295 // in: path 296 // description: name of the organization to get 297 // type: string 298 // required: true 299 // responses: 300 // "200": 301 // "$ref": "#/responses/Organization" 302 // "404": 303 // "$ref": "#/responses/notFound" 304 305 if !organization.HasOrgOrUserVisible(ctx, ctx.Org.Organization.AsUser(), ctx.Doer) { 306 ctx.NotFound("HasOrgOrUserVisible", nil) 307 return 308 } 309 310 org := convert.ToOrganization(ctx, ctx.Org.Organization) 311 312 // Don't show Mail, when User is not logged in 313 if ctx.Doer == nil { 314 org.Email = "" 315 } 316 317 ctx.JSON(http.StatusOK, org) 318 } 319 320 // Edit change an organization's information 321 func Edit(ctx *context.APIContext) { 322 // swagger:operation PATCH /orgs/{org} organization orgEdit 323 // --- 324 // summary: Edit an organization 325 // consumes: 326 // - application/json 327 // produces: 328 // - application/json 329 // parameters: 330 // - name: org 331 // in: path 332 // description: name of the organization to edit 333 // type: string 334 // required: true 335 // - name: body 336 // in: body 337 // required: true 338 // schema: 339 // "$ref": "#/definitions/EditOrgOption" 340 // responses: 341 // "200": 342 // "$ref": "#/responses/Organization" 343 // "404": 344 // "$ref": "#/responses/notFound" 345 form := web.GetForm(ctx).(*api.EditOrgOption) 346 org := ctx.Org.Organization 347 org.FullName = form.FullName 348 org.Email = form.Email 349 org.Description = form.Description 350 org.Website = form.Website 351 org.Location = form.Location 352 if form.Visibility != "" { 353 org.Visibility = api.VisibilityModes[form.Visibility] 354 } 355 if form.RepoAdminChangeTeamAccess != nil { 356 org.RepoAdminChangeTeamAccess = *form.RepoAdminChangeTeamAccess 357 } 358 if err := user_model.UpdateUserCols(ctx, org.AsUser(), 359 "full_name", "description", "website", "location", 360 "visibility", "repo_admin_change_team_access", 361 ); err != nil { 362 ctx.Error(http.StatusInternalServerError, "EditOrganization", err) 363 return 364 } 365 366 ctx.JSON(http.StatusOK, convert.ToOrganization(ctx, org)) 367 } 368 369 // Delete an organization 370 func Delete(ctx *context.APIContext) { 371 // swagger:operation DELETE /orgs/{org} organization orgDelete 372 // --- 373 // summary: Delete an organization 374 // produces: 375 // - application/json 376 // parameters: 377 // - name: org 378 // in: path 379 // description: organization that is to be deleted 380 // type: string 381 // required: true 382 // responses: 383 // "204": 384 // "$ref": "#/responses/empty" 385 // "404": 386 // "$ref": "#/responses/notFound" 387 388 if err := org.DeleteOrganization(ctx, ctx.Org.Organization, false); err != nil { 389 ctx.Error(http.StatusInternalServerError, "DeleteOrganization", err) 390 return 391 } 392 ctx.Status(http.StatusNoContent) 393 } 394 395 func ListOrgActivityFeeds(ctx *context.APIContext) { 396 // swagger:operation GET /orgs/{org}/activities/feeds organization orgListActivityFeeds 397 // --- 398 // summary: List an organization's activity feeds 399 // produces: 400 // - application/json 401 // parameters: 402 // - name: org 403 // in: path 404 // description: name of the org 405 // type: string 406 // required: true 407 // - name: date 408 // in: query 409 // description: the date of the activities to be found 410 // type: string 411 // format: date 412 // - name: page 413 // in: query 414 // description: page number of results to return (1-based) 415 // type: integer 416 // - name: limit 417 // in: query 418 // description: page size of results 419 // type: integer 420 // responses: 421 // "200": 422 // "$ref": "#/responses/ActivityFeedsList" 423 // "404": 424 // "$ref": "#/responses/notFound" 425 426 includePrivate := false 427 if ctx.IsSigned { 428 if ctx.Doer.IsAdmin { 429 includePrivate = true 430 } else { 431 org := organization.OrgFromUser(ctx.ContextUser) 432 isMember, err := org.IsOrgMember(ctx.Doer.ID) 433 if err != nil { 434 ctx.Error(http.StatusInternalServerError, "IsOrgMember", err) 435 return 436 } 437 includePrivate = isMember 438 } 439 } 440 441 listOptions := utils.GetListOptions(ctx) 442 443 opts := activities_model.GetFeedsOptions{ 444 RequestedUser: ctx.ContextUser, 445 Actor: ctx.Doer, 446 IncludePrivate: includePrivate, 447 Date: ctx.FormString("date"), 448 ListOptions: listOptions, 449 } 450 451 feeds, count, err := activities_model.GetFeeds(ctx, opts) 452 if err != nil { 453 ctx.Error(http.StatusInternalServerError, "GetFeeds", err) 454 return 455 } 456 ctx.SetTotalCountHeader(count) 457 458 ctx.JSON(http.StatusOK, convert.ToActivities(ctx, feeds, ctx.Doer)) 459 }