code.gitea.io/gitea@v1.21.7/routers/api/v1/org/team.go (about) 1 // Copyright 2016 The Gogs Authors. All rights reserved. 2 // Copyright 2019 The Gitea Authors. All rights reserved. 3 // SPDX-License-Identifier: MIT 4 5 package org 6 7 import ( 8 "errors" 9 "net/http" 10 11 "code.gitea.io/gitea/models" 12 activities_model "code.gitea.io/gitea/models/activities" 13 "code.gitea.io/gitea/models/organization" 14 "code.gitea.io/gitea/models/perm" 15 access_model "code.gitea.io/gitea/models/perm/access" 16 repo_model "code.gitea.io/gitea/models/repo" 17 unit_model "code.gitea.io/gitea/models/unit" 18 "code.gitea.io/gitea/modules/context" 19 "code.gitea.io/gitea/modules/log" 20 api "code.gitea.io/gitea/modules/structs" 21 "code.gitea.io/gitea/modules/web" 22 "code.gitea.io/gitea/routers/api/v1/user" 23 "code.gitea.io/gitea/routers/api/v1/utils" 24 "code.gitea.io/gitea/services/convert" 25 org_service "code.gitea.io/gitea/services/org" 26 repo_service "code.gitea.io/gitea/services/repository" 27 ) 28 29 // ListTeams list all the teams of an organization 30 func ListTeams(ctx *context.APIContext) { 31 // swagger:operation GET /orgs/{org}/teams organization orgListTeams 32 // --- 33 // summary: List an organization's teams 34 // produces: 35 // - application/json 36 // parameters: 37 // - name: org 38 // in: path 39 // description: name of the organization 40 // type: string 41 // required: true 42 // - name: page 43 // in: query 44 // description: page number of results to return (1-based) 45 // type: integer 46 // - name: limit 47 // in: query 48 // description: page size of results 49 // type: integer 50 // responses: 51 // "200": 52 // "$ref": "#/responses/TeamList" 53 // "404": 54 // "$ref": "#/responses/notFound" 55 56 teams, count, err := organization.SearchTeam(ctx, &organization.SearchTeamOptions{ 57 ListOptions: utils.GetListOptions(ctx), 58 OrgID: ctx.Org.Organization.ID, 59 }) 60 if err != nil { 61 ctx.Error(http.StatusInternalServerError, "LoadTeams", err) 62 return 63 } 64 65 apiTeams, err := convert.ToTeams(ctx, teams, false) 66 if err != nil { 67 ctx.Error(http.StatusInternalServerError, "ConvertToTeams", err) 68 return 69 } 70 71 ctx.SetTotalCountHeader(count) 72 ctx.JSON(http.StatusOK, apiTeams) 73 } 74 75 // ListUserTeams list all the teams a user belongs to 76 func ListUserTeams(ctx *context.APIContext) { 77 // swagger:operation GET /user/teams user userListTeams 78 // --- 79 // summary: List all the teams a user belongs to 80 // produces: 81 // - application/json 82 // parameters: 83 // - name: page 84 // in: query 85 // description: page number of results to return (1-based) 86 // type: integer 87 // - name: limit 88 // in: query 89 // description: page size of results 90 // type: integer 91 // responses: 92 // "200": 93 // "$ref": "#/responses/TeamList" 94 95 teams, count, err := organization.SearchTeam(ctx, &organization.SearchTeamOptions{ 96 ListOptions: utils.GetListOptions(ctx), 97 UserID: ctx.Doer.ID, 98 }) 99 if err != nil { 100 ctx.Error(http.StatusInternalServerError, "GetUserTeams", err) 101 return 102 } 103 104 apiTeams, err := convert.ToTeams(ctx, teams, true) 105 if err != nil { 106 ctx.Error(http.StatusInternalServerError, "ConvertToTeams", err) 107 return 108 } 109 110 ctx.SetTotalCountHeader(count) 111 ctx.JSON(http.StatusOK, apiTeams) 112 } 113 114 // GetTeam api for get a team 115 func GetTeam(ctx *context.APIContext) { 116 // swagger:operation GET /teams/{id} organization orgGetTeam 117 // --- 118 // summary: Get a team 119 // produces: 120 // - application/json 121 // parameters: 122 // - name: id 123 // in: path 124 // description: id of the team to get 125 // type: integer 126 // format: int64 127 // required: true 128 // responses: 129 // "200": 130 // "$ref": "#/responses/Team" 131 // "404": 132 // "$ref": "#/responses/notFound" 133 134 apiTeam, err := convert.ToTeam(ctx, ctx.Org.Team, true) 135 if err != nil { 136 ctx.InternalServerError(err) 137 return 138 } 139 140 ctx.JSON(http.StatusOK, apiTeam) 141 } 142 143 func attachTeamUnits(team *organization.Team, units []string) { 144 unitTypes, _ := unit_model.FindUnitTypes(units...) 145 team.Units = make([]*organization.TeamUnit, 0, len(units)) 146 for _, tp := range unitTypes { 147 team.Units = append(team.Units, &organization.TeamUnit{ 148 OrgID: team.OrgID, 149 Type: tp, 150 AccessMode: team.AccessMode, 151 }) 152 } 153 } 154 155 func convertUnitsMap(unitsMap map[string]string) map[unit_model.Type]perm.AccessMode { 156 res := make(map[unit_model.Type]perm.AccessMode, len(unitsMap)) 157 for unitKey, p := range unitsMap { 158 res[unit_model.TypeFromKey(unitKey)] = perm.ParseAccessMode(p) 159 } 160 return res 161 } 162 163 func attachTeamUnitsMap(team *organization.Team, unitsMap map[string]string) { 164 team.Units = make([]*organization.TeamUnit, 0, len(unitsMap)) 165 for unitKey, p := range unitsMap { 166 team.Units = append(team.Units, &organization.TeamUnit{ 167 OrgID: team.OrgID, 168 Type: unit_model.TypeFromKey(unitKey), 169 AccessMode: perm.ParseAccessMode(p), 170 }) 171 } 172 } 173 174 func attachAdminTeamUnits(team *organization.Team) { 175 team.Units = make([]*organization.TeamUnit, 0, len(unit_model.AllRepoUnitTypes)) 176 for _, ut := range unit_model.AllRepoUnitTypes { 177 up := perm.AccessModeAdmin 178 if ut == unit_model.TypeExternalTracker || ut == unit_model.TypeExternalWiki { 179 up = perm.AccessModeRead 180 } 181 team.Units = append(team.Units, &organization.TeamUnit{ 182 OrgID: team.OrgID, 183 Type: ut, 184 AccessMode: up, 185 }) 186 } 187 } 188 189 // CreateTeam api for create a team 190 func CreateTeam(ctx *context.APIContext) { 191 // swagger:operation POST /orgs/{org}/teams organization orgCreateTeam 192 // --- 193 // summary: Create a team 194 // consumes: 195 // - application/json 196 // produces: 197 // - application/json 198 // parameters: 199 // - name: org 200 // in: path 201 // description: name of the organization 202 // type: string 203 // required: true 204 // - name: body 205 // in: body 206 // schema: 207 // "$ref": "#/definitions/CreateTeamOption" 208 // responses: 209 // "201": 210 // "$ref": "#/responses/Team" 211 // "404": 212 // "$ref": "#/responses/notFound" 213 // "422": 214 // "$ref": "#/responses/validationError" 215 form := web.GetForm(ctx).(*api.CreateTeamOption) 216 p := perm.ParseAccessMode(form.Permission) 217 if p < perm.AccessModeAdmin && len(form.UnitsMap) > 0 { 218 p = unit_model.MinUnitAccessMode(convertUnitsMap(form.UnitsMap)) 219 } 220 team := &organization.Team{ 221 OrgID: ctx.Org.Organization.ID, 222 Name: form.Name, 223 Description: form.Description, 224 IncludesAllRepositories: form.IncludesAllRepositories, 225 CanCreateOrgRepo: form.CanCreateOrgRepo, 226 AccessMode: p, 227 } 228 229 if team.AccessMode < perm.AccessModeAdmin { 230 if len(form.UnitsMap) > 0 { 231 attachTeamUnitsMap(team, form.UnitsMap) 232 } else if len(form.Units) > 0 { 233 attachTeamUnits(team, form.Units) 234 } else { 235 ctx.Error(http.StatusInternalServerError, "getTeamUnits", errors.New("units permission should not be empty")) 236 return 237 } 238 } else { 239 attachAdminTeamUnits(team) 240 } 241 242 if err := models.NewTeam(ctx, team); err != nil { 243 if organization.IsErrTeamAlreadyExist(err) { 244 ctx.Error(http.StatusUnprocessableEntity, "", err) 245 } else { 246 ctx.Error(http.StatusInternalServerError, "NewTeam", err) 247 } 248 return 249 } 250 251 apiTeam, err := convert.ToTeam(ctx, team, true) 252 if err != nil { 253 ctx.InternalServerError(err) 254 return 255 } 256 ctx.JSON(http.StatusCreated, apiTeam) 257 } 258 259 // EditTeam api for edit a team 260 func EditTeam(ctx *context.APIContext) { 261 // swagger:operation PATCH /teams/{id} organization orgEditTeam 262 // --- 263 // summary: Edit a team 264 // consumes: 265 // - application/json 266 // produces: 267 // - application/json 268 // parameters: 269 // - name: id 270 // in: path 271 // description: id of the team to edit 272 // type: integer 273 // required: true 274 // - name: body 275 // in: body 276 // schema: 277 // "$ref": "#/definitions/EditTeamOption" 278 // responses: 279 // "200": 280 // "$ref": "#/responses/Team" 281 // "404": 282 // "$ref": "#/responses/notFound" 283 284 form := web.GetForm(ctx).(*api.EditTeamOption) 285 team := ctx.Org.Team 286 if err := team.LoadUnits(ctx); err != nil { 287 ctx.InternalServerError(err) 288 return 289 } 290 291 if form.CanCreateOrgRepo != nil { 292 team.CanCreateOrgRepo = team.IsOwnerTeam() || *form.CanCreateOrgRepo 293 } 294 295 if len(form.Name) > 0 { 296 team.Name = form.Name 297 } 298 299 if form.Description != nil { 300 team.Description = *form.Description 301 } 302 303 isAuthChanged := false 304 isIncludeAllChanged := false 305 if !team.IsOwnerTeam() && len(form.Permission) != 0 { 306 // Validate permission level. 307 p := perm.ParseAccessMode(form.Permission) 308 if p < perm.AccessModeAdmin && len(form.UnitsMap) > 0 { 309 p = unit_model.MinUnitAccessMode(convertUnitsMap(form.UnitsMap)) 310 } 311 312 if team.AccessMode != p { 313 isAuthChanged = true 314 team.AccessMode = p 315 } 316 317 if form.IncludesAllRepositories != nil { 318 isIncludeAllChanged = true 319 team.IncludesAllRepositories = *form.IncludesAllRepositories 320 } 321 } 322 323 if team.AccessMode < perm.AccessModeAdmin { 324 if len(form.UnitsMap) > 0 { 325 attachTeamUnitsMap(team, form.UnitsMap) 326 } else if len(form.Units) > 0 { 327 attachTeamUnits(team, form.Units) 328 } 329 } else { 330 attachAdminTeamUnits(team) 331 } 332 333 if err := models.UpdateTeam(ctx, team, isAuthChanged, isIncludeAllChanged); err != nil { 334 ctx.Error(http.StatusInternalServerError, "EditTeam", err) 335 return 336 } 337 338 apiTeam, err := convert.ToTeam(ctx, team) 339 if err != nil { 340 ctx.InternalServerError(err) 341 return 342 } 343 ctx.JSON(http.StatusOK, apiTeam) 344 } 345 346 // DeleteTeam api for delete a team 347 func DeleteTeam(ctx *context.APIContext) { 348 // swagger:operation DELETE /teams/{id} organization orgDeleteTeam 349 // --- 350 // summary: Delete a team 351 // parameters: 352 // - name: id 353 // in: path 354 // description: id of the team to delete 355 // type: integer 356 // format: int64 357 // required: true 358 // responses: 359 // "204": 360 // description: team deleted 361 // "404": 362 // "$ref": "#/responses/notFound" 363 364 if err := models.DeleteTeam(ctx, ctx.Org.Team); err != nil { 365 ctx.Error(http.StatusInternalServerError, "DeleteTeam", err) 366 return 367 } 368 ctx.Status(http.StatusNoContent) 369 } 370 371 // GetTeamMembers api for get a team's members 372 func GetTeamMembers(ctx *context.APIContext) { 373 // swagger:operation GET /teams/{id}/members organization orgListTeamMembers 374 // --- 375 // summary: List a team's members 376 // produces: 377 // - application/json 378 // parameters: 379 // - name: id 380 // in: path 381 // description: id of the team 382 // type: integer 383 // format: int64 384 // required: true 385 // - name: page 386 // in: query 387 // description: page number of results to return (1-based) 388 // type: integer 389 // - name: limit 390 // in: query 391 // description: page size of results 392 // type: integer 393 // responses: 394 // "200": 395 // "$ref": "#/responses/UserList" 396 // "404": 397 // "$ref": "#/responses/notFound" 398 399 isMember, err := organization.IsOrganizationMember(ctx, ctx.Org.Team.OrgID, ctx.Doer.ID) 400 if err != nil { 401 ctx.Error(http.StatusInternalServerError, "IsOrganizationMember", err) 402 return 403 } else if !isMember && !ctx.Doer.IsAdmin { 404 ctx.NotFound() 405 return 406 } 407 408 teamMembers, err := organization.GetTeamMembers(ctx, &organization.SearchMembersOptions{ 409 ListOptions: utils.GetListOptions(ctx), 410 TeamID: ctx.Org.Team.ID, 411 }) 412 if err != nil { 413 ctx.Error(http.StatusInternalServerError, "GetTeamMembers", err) 414 return 415 } 416 417 members := make([]*api.User, len(teamMembers)) 418 for i, member := range teamMembers { 419 members[i] = convert.ToUser(ctx, member, ctx.Doer) 420 } 421 422 ctx.SetTotalCountHeader(int64(ctx.Org.Team.NumMembers)) 423 ctx.JSON(http.StatusOK, members) 424 } 425 426 // GetTeamMember api for get a particular member of team 427 func GetTeamMember(ctx *context.APIContext) { 428 // swagger:operation GET /teams/{id}/members/{username} organization orgListTeamMember 429 // --- 430 // summary: List a particular member of team 431 // produces: 432 // - application/json 433 // parameters: 434 // - name: id 435 // in: path 436 // description: id of the team 437 // type: integer 438 // format: int64 439 // required: true 440 // - name: username 441 // in: path 442 // description: username of the member to list 443 // type: string 444 // required: true 445 // responses: 446 // "200": 447 // "$ref": "#/responses/User" 448 // "404": 449 // "$ref": "#/responses/notFound" 450 451 u := user.GetUserByParams(ctx) 452 if ctx.Written() { 453 return 454 } 455 teamID := ctx.ParamsInt64("teamid") 456 isTeamMember, err := organization.IsUserInTeams(ctx, u.ID, []int64{teamID}) 457 if err != nil { 458 ctx.Error(http.StatusInternalServerError, "IsUserInTeams", err) 459 return 460 } else if !isTeamMember { 461 ctx.NotFound() 462 return 463 } 464 ctx.JSON(http.StatusOK, convert.ToUser(ctx, u, ctx.Doer)) 465 } 466 467 // AddTeamMember api for add a member to a team 468 func AddTeamMember(ctx *context.APIContext) { 469 // swagger:operation PUT /teams/{id}/members/{username} organization orgAddTeamMember 470 // --- 471 // summary: Add a team member 472 // produces: 473 // - application/json 474 // parameters: 475 // - name: id 476 // in: path 477 // description: id of the team 478 // type: integer 479 // format: int64 480 // required: true 481 // - name: username 482 // in: path 483 // description: username of the user to add 484 // type: string 485 // required: true 486 // responses: 487 // "204": 488 // "$ref": "#/responses/empty" 489 // "404": 490 // "$ref": "#/responses/notFound" 491 492 u := user.GetUserByParams(ctx) 493 if ctx.Written() { 494 return 495 } 496 if err := models.AddTeamMember(ctx, ctx.Org.Team, u.ID); err != nil { 497 ctx.Error(http.StatusInternalServerError, "AddMember", err) 498 return 499 } 500 ctx.Status(http.StatusNoContent) 501 } 502 503 // RemoveTeamMember api for remove one member from a team 504 func RemoveTeamMember(ctx *context.APIContext) { 505 // swagger:operation DELETE /teams/{id}/members/{username} organization orgRemoveTeamMember 506 // --- 507 // summary: Remove a team member 508 // produces: 509 // - application/json 510 // parameters: 511 // - name: id 512 // in: path 513 // description: id of the team 514 // type: integer 515 // format: int64 516 // required: true 517 // - name: username 518 // in: path 519 // description: username of the user to remove 520 // type: string 521 // required: true 522 // responses: 523 // "204": 524 // "$ref": "#/responses/empty" 525 // "404": 526 // "$ref": "#/responses/notFound" 527 528 u := user.GetUserByParams(ctx) 529 if ctx.Written() { 530 return 531 } 532 533 if err := models.RemoveTeamMember(ctx, ctx.Org.Team, u.ID); err != nil { 534 ctx.Error(http.StatusInternalServerError, "RemoveTeamMember", err) 535 return 536 } 537 ctx.Status(http.StatusNoContent) 538 } 539 540 // GetTeamRepos api for get a team's repos 541 func GetTeamRepos(ctx *context.APIContext) { 542 // swagger:operation GET /teams/{id}/repos organization orgListTeamRepos 543 // --- 544 // summary: List a team's repos 545 // produces: 546 // - application/json 547 // parameters: 548 // - name: id 549 // in: path 550 // description: id of the team 551 // type: integer 552 // format: int64 553 // required: true 554 // - name: page 555 // in: query 556 // description: page number of results to return (1-based) 557 // type: integer 558 // - name: limit 559 // in: query 560 // description: page size of results 561 // type: integer 562 // responses: 563 // "200": 564 // "$ref": "#/responses/RepositoryList" 565 // "404": 566 // "$ref": "#/responses/notFound" 567 568 team := ctx.Org.Team 569 teamRepos, err := organization.GetTeamRepositories(ctx, &organization.SearchTeamRepoOptions{ 570 ListOptions: utils.GetListOptions(ctx), 571 TeamID: team.ID, 572 }) 573 if err != nil { 574 ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err) 575 return 576 } 577 repos := make([]*api.Repository, len(teamRepos)) 578 for i, repo := range teamRepos { 579 permission, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer) 580 if err != nil { 581 ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err) 582 return 583 } 584 repos[i] = convert.ToRepo(ctx, repo, permission) 585 } 586 ctx.SetTotalCountHeader(int64(team.NumRepos)) 587 ctx.JSON(http.StatusOK, repos) 588 } 589 590 // GetTeamRepo api for get a particular repo of team 591 func GetTeamRepo(ctx *context.APIContext) { 592 // swagger:operation GET /teams/{id}/repos/{org}/{repo} organization orgListTeamRepo 593 // --- 594 // summary: List a particular repo of team 595 // produces: 596 // - application/json 597 // parameters: 598 // - name: id 599 // in: path 600 // description: id of the team 601 // type: integer 602 // format: int64 603 // required: true 604 // - name: org 605 // in: path 606 // description: organization that owns the repo to list 607 // type: string 608 // required: true 609 // - name: repo 610 // in: path 611 // description: name of the repo to list 612 // type: string 613 // required: true 614 // responses: 615 // "200": 616 // "$ref": "#/responses/Repository" 617 // "404": 618 // "$ref": "#/responses/notFound" 619 620 repo := getRepositoryByParams(ctx) 621 if ctx.Written() { 622 return 623 } 624 625 if !organization.HasTeamRepo(ctx, ctx.Org.Team.OrgID, ctx.Org.Team.ID, repo.ID) { 626 ctx.NotFound() 627 return 628 } 629 630 permission, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer) 631 if err != nil { 632 ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err) 633 return 634 } 635 636 ctx.JSON(http.StatusOK, convert.ToRepo(ctx, repo, permission)) 637 } 638 639 // getRepositoryByParams get repository by a team's organization ID and repo name 640 func getRepositoryByParams(ctx *context.APIContext) *repo_model.Repository { 641 repo, err := repo_model.GetRepositoryByName(ctx.Org.Team.OrgID, ctx.Params(":reponame")) 642 if err != nil { 643 if repo_model.IsErrRepoNotExist(err) { 644 ctx.NotFound() 645 } else { 646 ctx.Error(http.StatusInternalServerError, "GetRepositoryByName", err) 647 } 648 return nil 649 } 650 return repo 651 } 652 653 // AddTeamRepository api for adding a repository to a team 654 func AddTeamRepository(ctx *context.APIContext) { 655 // swagger:operation PUT /teams/{id}/repos/{org}/{repo} organization orgAddTeamRepository 656 // --- 657 // summary: Add a repository to a team 658 // produces: 659 // - application/json 660 // parameters: 661 // - name: id 662 // in: path 663 // description: id of the team 664 // type: integer 665 // format: int64 666 // required: true 667 // - name: org 668 // in: path 669 // description: organization that owns the repo to add 670 // type: string 671 // required: true 672 // - name: repo 673 // in: path 674 // description: name of the repo to add 675 // type: string 676 // required: true 677 // responses: 678 // "204": 679 // "$ref": "#/responses/empty" 680 // "403": 681 // "$ref": "#/responses/forbidden" 682 // "404": 683 // "$ref": "#/responses/notFound" 684 685 repo := getRepositoryByParams(ctx) 686 if ctx.Written() { 687 return 688 } 689 if access, err := access_model.AccessLevel(ctx, ctx.Doer, repo); err != nil { 690 ctx.Error(http.StatusInternalServerError, "AccessLevel", err) 691 return 692 } else if access < perm.AccessModeAdmin { 693 ctx.Error(http.StatusForbidden, "", "Must have admin-level access to the repository") 694 return 695 } 696 if err := org_service.TeamAddRepository(ctx, ctx.Org.Team, repo); err != nil { 697 ctx.Error(http.StatusInternalServerError, "TeamAddRepository", err) 698 return 699 } 700 ctx.Status(http.StatusNoContent) 701 } 702 703 // RemoveTeamRepository api for removing a repository from a team 704 func RemoveTeamRepository(ctx *context.APIContext) { 705 // swagger:operation DELETE /teams/{id}/repos/{org}/{repo} organization orgRemoveTeamRepository 706 // --- 707 // summary: Remove a repository from a team 708 // description: This does not delete the repository, it only removes the 709 // repository from the team. 710 // produces: 711 // - application/json 712 // parameters: 713 // - name: id 714 // in: path 715 // description: id of the team 716 // type: integer 717 // format: int64 718 // required: true 719 // - name: org 720 // in: path 721 // description: organization that owns the repo to remove 722 // type: string 723 // required: true 724 // - name: repo 725 // in: path 726 // description: name of the repo to remove 727 // type: string 728 // required: true 729 // responses: 730 // "204": 731 // "$ref": "#/responses/empty" 732 // "403": 733 // "$ref": "#/responses/forbidden" 734 // "404": 735 // "$ref": "#/responses/notFound" 736 737 repo := getRepositoryByParams(ctx) 738 if ctx.Written() { 739 return 740 } 741 if access, err := access_model.AccessLevel(ctx, ctx.Doer, repo); err != nil { 742 ctx.Error(http.StatusInternalServerError, "AccessLevel", err) 743 return 744 } else if access < perm.AccessModeAdmin { 745 ctx.Error(http.StatusForbidden, "", "Must have admin-level access to the repository") 746 return 747 } 748 if err := repo_service.RemoveRepositoryFromTeam(ctx, ctx.Org.Team, repo.ID); err != nil { 749 ctx.Error(http.StatusInternalServerError, "RemoveRepository", err) 750 return 751 } 752 ctx.Status(http.StatusNoContent) 753 } 754 755 // SearchTeam api for searching teams 756 func SearchTeam(ctx *context.APIContext) { 757 // swagger:operation GET /orgs/{org}/teams/search organization teamSearch 758 // --- 759 // summary: Search for teams within an organization 760 // produces: 761 // - application/json 762 // parameters: 763 // - name: org 764 // in: path 765 // description: name of the organization 766 // type: string 767 // required: true 768 // - name: q 769 // in: query 770 // description: keywords to search 771 // type: string 772 // - name: include_desc 773 // in: query 774 // description: include search within team description (defaults to true) 775 // type: boolean 776 // - name: page 777 // in: query 778 // description: page number of results to return (1-based) 779 // type: integer 780 // - name: limit 781 // in: query 782 // description: page size of results 783 // type: integer 784 // responses: 785 // "200": 786 // description: "SearchResults of a successful search" 787 // schema: 788 // type: object 789 // properties: 790 // ok: 791 // type: boolean 792 // data: 793 // type: array 794 // items: 795 // "$ref": "#/definitions/Team" 796 // "404": 797 // "$ref": "#/responses/notFound" 798 799 listOptions := utils.GetListOptions(ctx) 800 801 opts := &organization.SearchTeamOptions{ 802 Keyword: ctx.FormTrim("q"), 803 OrgID: ctx.Org.Organization.ID, 804 IncludeDesc: ctx.FormString("include_desc") == "" || ctx.FormBool("include_desc"), 805 ListOptions: listOptions, 806 } 807 808 // Only admin is allowd to search for all teams 809 if !ctx.Doer.IsAdmin { 810 opts.UserID = ctx.Doer.ID 811 } 812 813 teams, maxResults, err := organization.SearchTeam(ctx, opts) 814 if err != nil { 815 log.Error("SearchTeam failed: %v", err) 816 ctx.JSON(http.StatusInternalServerError, map[string]any{ 817 "ok": false, 818 "error": "SearchTeam internal failure", 819 }) 820 return 821 } 822 823 apiTeams, err := convert.ToTeams(ctx, teams, false) 824 if err != nil { 825 ctx.InternalServerError(err) 826 return 827 } 828 829 ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) 830 ctx.SetTotalCountHeader(maxResults) 831 ctx.JSON(http.StatusOK, map[string]any{ 832 "ok": true, 833 "data": apiTeams, 834 }) 835 } 836 837 func ListTeamActivityFeeds(ctx *context.APIContext) { 838 // swagger:operation GET /teams/{id}/activities/feeds organization orgListTeamActivityFeeds 839 // --- 840 // summary: List a team's activity feeds 841 // produces: 842 // - application/json 843 // parameters: 844 // - name: id 845 // in: path 846 // description: id of the team 847 // type: integer 848 // format: int64 849 // required: true 850 // - name: date 851 // in: query 852 // description: the date of the activities to be found 853 // type: string 854 // format: date 855 // - name: page 856 // in: query 857 // description: page number of results to return (1-based) 858 // type: integer 859 // - name: limit 860 // in: query 861 // description: page size of results 862 // type: integer 863 // responses: 864 // "200": 865 // "$ref": "#/responses/ActivityFeedsList" 866 // "404": 867 // "$ref": "#/responses/notFound" 868 869 listOptions := utils.GetListOptions(ctx) 870 871 opts := activities_model.GetFeedsOptions{ 872 RequestedTeam: ctx.Org.Team, 873 Actor: ctx.Doer, 874 IncludePrivate: true, 875 Date: ctx.FormString("date"), 876 ListOptions: listOptions, 877 } 878 879 feeds, count, err := activities_model.GetFeeds(ctx, opts) 880 if err != nil { 881 ctx.Error(http.StatusInternalServerError, "GetFeeds", err) 882 return 883 } 884 ctx.SetTotalCountHeader(count) 885 886 ctx.JSON(http.StatusOK, convert.ToActivities(ctx, feeds, ctx.Doer)) 887 }