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  }