diff --git a/config.yml.sample b/config.yml.sample index acbb5a300..10f30b0d4 100644 --- a/config.yml.sample +++ b/config.yml.sample @@ -62,6 +62,9 @@ service: allowiconchanges: true # Allow using a custom logo via external URL. customlogourl: '' + # Enables the public team feature. If enabled, it is possible to configure teams to be public, which makes them + # discoverable when sharing a project, therefore not only showing teams the user is member of. + enablepublicteams: false sentry: # If set to true, enables anonymous error tracking of api errors via Sentry. This allows us to gather more diff --git a/docs/content/doc/setup/config.md b/docs/content/doc/setup/config.md index a68bf22b5..c5210edec 100644 --- a/docs/content/doc/setup/config.md +++ b/docs/content/doc/setup/config.md @@ -346,6 +346,17 @@ Full path: `service.customlogourl` Environment path: `VIKUNJA_SERVICE_CUSTOMLOGOURL` +### enablepublicteams + +discoverable when sharing a project, therefore not only showing teams the user is member of. + +Default: `false` + +Full path: `service.enablepublicteams` + +Environment path: `VIKUNJA_SERVICE_ENABLEPUBLICTEAMS` + + --- ## sentry diff --git a/docs/content/doc/setup/openid.md b/docs/content/doc/setup/openid.md index 320c2a725..b0e66e69c 100644 --- a/docs/content/doc/setup/openid.md +++ b/docs/content/doc/setup/openid.md @@ -99,7 +99,7 @@ It depends on the provider being used as well as the preferences of the administ Typically you'd want to request an additional scope (e.g. `vikunja_scope`) which then triggers the identity provider to add the claim. If the `vikunja_groups` is part of the **ID token**, Vikunja will start the procedure and import teams and team memberships. -The claim structure expexted by Vikunja is as follows: +The minimal claim structure expected by Vikunja is as follows: ```json { @@ -116,6 +116,21 @@ The claim structure expexted by Vikunja is as follows: } ``` +It also also possible to pass the description and isPublic flag as optional parameter. If not present, the description will be empty and project visibility defaults to false. + +```json +{ + "vikunja_groups": [ + { + "name": "team 3", + "oidcID": 33349, + "description": "My Team Description", + "isPublic": true + }, + ] +} +``` + For each team, you need to define a team `name` and an `oidcID`, where the `oidcID` can be any string with a length of less than 250 characters. The `oidcID` is used to uniquely identify the team, so please make sure to keep this unique. diff --git a/frontend/src/components/sharing/userTeam.vue b/frontend/src/components/sharing/userTeam.vue index 3858c6ab5..535b8cdbb 100644 --- a/frontend/src/components/sharing/userTeam.vue +++ b/frontend/src/components/sharing/userTeam.vue @@ -172,6 +172,7 @@ import Multiselect from '@/components/input/multiselect.vue' import Nothing from '@/components/misc/nothing.vue' import {success} from '@/message' import {useAuthStore} from '@/stores/auth' +import {useConfigStore} from '@/stores/config' // FIXME: I think this whole thing can now only manage user/team sharing for projects? Maybe remove a little generalization? @@ -210,8 +211,8 @@ const selectedRight = ref({}) const sharables = ref([]) const showDeleteModal = ref(false) - const authStore = useAuthStore() +const configStore = useConfigStore() const userInfo = computed(() => authStore.info) function createShareTypeNameComputed(count: number) { @@ -360,7 +361,15 @@ async function find(query: string) { found.value = [] return } - const results = await searchService.getAll({}, {s: query}) + + // Include public teams here if we are sharing with teams and its enabled in the config + let results = [] + if (props.shareType === 'team' && configStore.publicTeamsEnabled) { + results = await searchService.getAll({}, {s: query, includePublic: true}) + } else { + results = await searchService.getAll({}, {s: query}) + } + found.value = results .filter(m => { if(props.shareType === 'user' && m.id === currentUserId.value) { diff --git a/frontend/src/i18n/lang/en.json b/frontend/src/i18n/lang/en.json index 652b43450..b7747ecb7 100644 --- a/frontend/src/i18n/lang/en.json +++ b/frontend/src/i18n/lang/en.json @@ -986,7 +986,9 @@ "description": "Description", "descriptionPlaceholder": "Describe the team here, hit '/' for more options…", "admin": "Admin", - "member": "Member" + "member": "Member", + "isPublic": "Public Team", + "isPublicDescription": "Make the team publicly discoverable. When enabled, anyone can share projects with this team even when not being a direct member." } }, "keyboardShortcuts": { diff --git a/frontend/src/modelTypes/ITeam.ts b/frontend/src/modelTypes/ITeam.ts index 3cdaae987..e9e7142cb 100644 --- a/frontend/src/modelTypes/ITeam.ts +++ b/frontend/src/modelTypes/ITeam.ts @@ -10,6 +10,7 @@ export interface ITeam extends IAbstract { members: ITeamMember[] right: Right oidcId: string + isPublic: boolean createdBy: IUser created: Date diff --git a/frontend/src/models/team.ts b/frontend/src/models/team.ts index 1e75738bb..cc17849fa 100644 --- a/frontend/src/models/team.ts +++ b/frontend/src/models/team.ts @@ -14,6 +14,7 @@ export default class TeamModel extends AbstractModel implements ITeam { members: ITeamMember[] = [] right: Right = RIGHTS.READ oidcId = '' + isPublic: boolean = false createdBy: IUser = {} // FIXME: seems wrong created: Date = null diff --git a/frontend/src/stores/config.ts b/frontend/src/stores/config.ts index c5dbe6973..eb09372da 100644 --- a/frontend/src/stores/config.ts +++ b/frontend/src/stores/config.ts @@ -37,6 +37,7 @@ export interface ConfigState { providers: IProvider[], }, }, + publicTeamsEnabled: boolean, } export const useConfigStore = defineStore('config', () => { @@ -70,6 +71,7 @@ export const useConfigStore = defineStore('config', () => { providers: [], }, }, + publicTeamsEnabled: false, }) const migratorsEnabled = computed(() => state.availableMigrators?.length > 0) diff --git a/frontend/src/views/teams/EditTeam.vue b/frontend/src/views/teams/EditTeam.vue index 993f2e6af..f435d4df8 100644 --- a/frontend/src/views/teams/EditTeam.vue +++ b/frontend/src/views/teams/EditTeam.vue @@ -33,6 +33,27 @@ > {{ $t('team.attributes.nameRequired') }}

+
+ +
+ + {{ $t('team.attributes.isPublicDescription') }} + +
+
+
+ +
+ + {{ $t('team.attributes.isPublicDescription') }} + +
+

t('team.create.title')) useTitle(title) @@ -60,6 +83,8 @@ const teamService = shallowReactive(new TeamService()) const team = reactive(new TeamModel()) const showError = ref(false) +const configStore = useConfigStore() + async function newTeam() { if (team.name === '') { showError.value = true diff --git a/pkg/config/config.go b/pkg/config/config.go index 0e82a6637..d8f904e52 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -64,6 +64,7 @@ const ( ServiceMaxAvatarSize Key = `service.maxavatarsize` ServiceAllowIconChanges Key = `service.allowiconchanges` ServiceCustomLogoURL Key = `service.customlogourl` + ServiceEnablePublicTeams Key = `service.enablepublicteams` SentryEnabled Key = `sentry.enabled` SentryDsn Key = `sentry.dsn` @@ -312,6 +313,7 @@ func InitDefaultConfig() { ServiceMaxAvatarSize.setDefault(1024) ServiceDemoMode.setDefault(false) ServiceAllowIconChanges.setDefault(true) + ServiceEnablePublicTeams.setDefault(false) // Sentry SentryDsn.setDefault("https://440eedc957d545a795c17bbaf477497c@o1047380.ingest.sentry.io/4504254983634944") diff --git a/pkg/db/fixtures/team_members.yml b/pkg/db/fixtures/team_members.yml index 889322b7b..2b260b329 100644 --- a/pkg/db/fixtures/team_members.yml +++ b/pkg/db/fixtures/team_members.yml @@ -1,61 +1,49 @@ -- - team_id: 1 +- team_id: 1 user_id: 1 admin: true created: 2018-12-01 15:13:12 -- - team_id: 1 +- team_id: 1 user_id: 2 created: 2018-12-01 15:13:12 -- - team_id: 2 +- team_id: 2 user_id: 1 created: 2018-12-01 15:13:12 -- - team_id: 3 +- team_id: 3 user_id: 1 created: 2018-12-01 15:13:12 -- - team_id: 4 +- team_id: 4 user_id: 1 created: 2018-12-01 15:13:12 -- - team_id: 5 +- team_id: 5 user_id: 1 created: 2018-12-01 15:13:12 -- - team_id: 6 +- team_id: 6 user_id: 1 created: 2018-12-01 15:13:12 -- - team_id: 7 +- team_id: 7 user_id: 1 created: 2018-12-01 15:13:12 -- - team_id: 8 +- team_id: 8 user_id: 1 created: 2018-12-01 15:13:12 -- - team_id: 9 +- team_id: 9 user_id: 2 created: 2018-12-01 15:13:12 -- - team_id: 10 +- team_id: 10 user_id: 3 created: 2018-12-01 15:13:12 -- - team_id: 11 +- team_id: 11 user_id: 8 created: 2018-12-01 15:13:12 -- - team_id: 12 +- team_id: 12 user_id: 9 created: 2018-12-01 15:13:12 -- - team_id: 13 +- team_id: 13 user_id: 10 created: 2018-12-01 15:13:12 -- - team_id: 14 +- team_id: 14 user_id: 10 - created: 2018-12-01 15:13:12 \ No newline at end of file + created: 2018-12-01 15:13:12 +- team_id: 15 + user_id: 10 + created: 2018-12-01 15:13:12 diff --git a/pkg/db/fixtures/teams.yml b/pkg/db/fixtures/teams.yml index aaba624a3..5c4f49ec7 100644 --- a/pkg/db/fixtures/teams.yml +++ b/pkg/db/fixtures/teams.yml @@ -29,8 +29,16 @@ - id: 13 name: testteam13 created_by_id: 7 + is_public: true - id: 14 name: testteam14 created_by_id: 7 oidc_id: 14 - issuer: "https://some.issuer" \ No newline at end of file + issuer: "https://some.issuer" +- id: 15 + name: testteam15 + created_by_id: 7 + oidc_id: 15 + issuer: "https://some.issuer" + is_public: true + description: "This is a public team" diff --git a/pkg/migration/20240309111148.go b/pkg/migration/20240309111148.go new file mode 100644 index 000000000..7b0aa4c83 --- /dev/null +++ b/pkg/migration/20240309111148.go @@ -0,0 +1,43 @@ +// Vikunja is a to-do list application to facilitate your life. +// Copyright 2018-present Vikunja and contributors. All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public Licensee as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public Licensee for more details. +// +// You should have received a copy of the GNU Affero General Public Licensee +// along with this program. If not, see . + +package migration + +import ( + "src.techknowlogick.com/xormigrate" + "xorm.io/xorm" +) + +type teams20240309111148 struct { + IsPublic bool `xorm:"not null default false" json:"is_public"` +} + +func (teams20240309111148) TableName() string { + return "teams" +} + +func init() { + migrations = append(migrations, &xormigrate.Migration{ + ID: "20240309111148", + Description: "Add IsPublic field to teams table to control discoverability of teams.", + Migrate: func(tx *xorm.Engine) error { + return tx.Sync2(teams20240309111148{}) + }, + Rollback: func(tx *xorm.Engine) error { + return nil + }, + }) +} diff --git a/pkg/models/teams.go b/pkg/models/teams.go index 648cbe919..8cae52324 100644 --- a/pkg/models/teams.go +++ b/pkg/models/teams.go @@ -19,6 +19,7 @@ package models import ( "time" + "code.vikunja.io/api/pkg/config" "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/events" @@ -53,6 +54,12 @@ type Team struct { // A timestamp when this relation was last updated. You cannot change this value. Updated time.Time `xorm:"updated" json:"updated"` + // Defines wether the team should be publicly discoverable when sharing a project + IsPublic bool `xorm:"not null default false" json:"is_public"` + + // Query parameter controlling whether to include public projects or not + IncludePublic bool `xorm:"-" query:"include_public" json:"include_public"` + web.CRUDable `xorm:"-" json:"-"` web.Rights `xorm:"-" json:"-"` } @@ -100,6 +107,7 @@ type OIDCTeam struct { Name string OidcID string Description string + IsPublic bool } // GetTeamByID gets a team by its ID @@ -287,11 +295,24 @@ func (t *Team) ReadAll(s *xorm.Session, a web.Auth, search string, page int, per limit, start := getLimitFromPageIndex(page, perPage) all := []*Team{} + query := s.Select("teams.*"). Table("teams"). Join("INNER", "team_members", "team_members.team_id = teams.id"). - Where("team_members.user_id = ?", a.GetID()). Where(db.ILIKE("teams.name", search)) + + // If public teams are enabled, we want to include them in the result + if config.ServiceEnablePublicTeams.GetBool() && t.IncludePublic { + query = query.Where( + builder.Or( + builder.Eq{"teams.is_public": true}, + builder.Eq{"team_members.user_id": a.GetID()}, + ), + ) + } else { + query = query.Where("team_members.user_id = ?", a.GetID()) + } + if limit > 0 { query = query.Limit(limit, start) } @@ -398,7 +419,7 @@ func (t *Team) Update(s *xorm.Session, _ web.Auth) (err error) { return } - _, err = s.ID(t.ID).Update(t) + _, err = s.ID(t.ID).UseBool("is_public").Update(t) if err != nil { return } diff --git a/pkg/models/teams_test.go b/pkg/models/teams_test.go index 627cbc249..4f0ccd2d2 100644 --- a/pkg/models/teams_test.go +++ b/pkg/models/teams_test.go @@ -20,6 +20,7 @@ import ( "reflect" "testing" + "code.vikunja.io/api/pkg/config" "code.vikunja.io/api/pkg/db" "code.vikunja.io/api/pkg/user" @@ -49,6 +50,7 @@ func TestTeam_Create(t *testing.T) { "id": team.ID, "name": "Testteam293", "description": "Lorem Ispum", + "is_public": false, }, false) }) t.Run("empty name", func(t *testing.T) { @@ -61,6 +63,27 @@ func TestTeam_Create(t *testing.T) { require.Error(t, err) assert.True(t, IsErrTeamNameCannotBeEmpty(err)) }) + t.Run("public", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + s := db.NewSession() + defer s.Close() + + team := &Team{ + Name: "Testteam293_Public", + Description: "Lorem Ispum", + IsPublic: true, + } + err := team.Create(s, doer) + require.NoError(t, err) + err = s.Commit() + require.NoError(t, err) + db.AssertExists(t, "teams", map[string]interface{}{ + "id": team.ID, + "name": "Testteam293_Public", + "description": "Lorem Ispum", + "is_public": true, + }, false) + }) } func TestTeam_ReadOne(t *testing.T) { @@ -126,6 +149,58 @@ func TestTeam_ReadAll(t *testing.T) { assert.Len(t, ts, 1) assert.Equal(t, int64(2), ts[0].ID) }) + t.Run("public discovery disabled", func(t *testing.T) { + + s := db.NewSession() + defer s.Close() + + team := &Team{} + + // Default setting is having ServiceEnablePublicTeams disabled + // In this default case, fetching teams with or without public flag should return the same result + + // Fetch without public flag + teams, _, _, err := team.ReadAll(s, doer, "", 1, 50) + require.NoError(t, err) + assert.Equal(t, reflect.Slice, reflect.TypeOf(teams).Kind()) + ts := teams.([]*Team) + assert.Len(t, ts, 5) + + // Fetch with public flag + team.IncludePublic = true + teams, _, _, err = team.ReadAll(s, doer, "", 1, 50) + require.NoError(t, err) + assert.Equal(t, reflect.Slice, reflect.TypeOf(teams).Kind()) + ts = teams.([]*Team) + assert.Len(t, ts, 5) + }) + + t.Run("public discovery enabled", func(t *testing.T) { + + s := db.NewSession() + defer s.Close() + + team := &Team{} + + // Enable ServiceEnablePublicTeams feature + config.ServiceEnablePublicTeams.Set(true) + + // Fetch without public flag should be the same as before + team.IncludePublic = false + teams, _, _, err := team.ReadAll(s, doer, "", 1, 50) + require.NoError(t, err) + assert.Equal(t, reflect.Slice, reflect.TypeOf(teams).Kind()) + ts := teams.([]*Team) + assert.Len(t, ts, 5) + + // Fetch with public flag should return more teams + team.IncludePublic = true + teams, _, _, err = team.ReadAll(s, doer, "", 1, 50) + require.NoError(t, err) + assert.Equal(t, reflect.Slice, reflect.TypeOf(teams).Kind()) + ts = teams.([]*Team) + assert.Len(t, ts, 7) + }) } func TestTeam_Update(t *testing.T) { diff --git a/pkg/modules/auth/openid/openid.go b/pkg/modules/auth/openid/openid.go index 1da50c06b..ad9655315 100644 --- a/pkg/modules/auth/openid/openid.go +++ b/pkg/modules/auth/openid/openid.go @@ -298,14 +298,27 @@ func getTeamDataFromToken(groups []map[string]interface{}, provider *Provider) ( var name string var description string var oidcID string + var IsPublic bool + + // Read name _, exists := team["name"] if exists { name = team["name"].(string) } + + // Read description _, exists = team["description"] if exists { description = team["description"].(string) } + + // Read isPublic flag + _, exists = team["isPublic"] + if exists { + IsPublic = team["isPublic"].(bool) + } + + // Read oidcID _, exists = team["oidcID"] if exists { switch t := team["oidcID"].(type) { @@ -324,7 +337,7 @@ func getTeamDataFromToken(groups []map[string]interface{}, provider *Provider) ( errs = append(errs, &user.ErrOpenIDCustomScopeMalformed{}) continue } - teamData = append(teamData, &models.OIDCTeam{Name: name, OidcID: oidcID, Description: description}) + teamData = append(teamData, &models.OIDCTeam{Name: name, OidcID: oidcID, Description: description, IsPublic: IsPublic}) } return teamData, errs } @@ -339,6 +352,7 @@ func CreateOIDCTeam(s *xorm.Session, teamData *models.OIDCTeam, u *user.User, is Description: teamData.Description, OidcID: teamData.OidcID, Issuer: issuer, + IsPublic: teamData.IsPublic, } err = team.CreateNewTeam(s, u, false) return team, err @@ -363,12 +377,24 @@ func GetOrCreateTeamsByOIDC(s *xorm.Session, teamData []*models.OIDCTeam, u *use continue } + // Compare the name and update if it changed if team.Name != getOIDCTeamName(oidcTeam.Name) { team.Name = getOIDCTeamName(oidcTeam.Name) - err = team.Update(s, u) - if err != nil { - return nil, err - } + } + + // Compare the description and update if it changed + if team.Description != oidcTeam.Description { + team.Description = oidcTeam.Description + } + + // Compare the isPublic flag and update if it changed + if team.IsPublic != oidcTeam.IsPublic { + team.IsPublic = oidcTeam.IsPublic + } + + err = team.Update(s, u) + if err != nil { + return nil, err } log.Debugf("Team with oidc_id %v and name %v already exists.", team.OidcID, team.Name) diff --git a/pkg/modules/auth/openid/openid_test.go b/pkg/modules/auth/openid/openid_test.go index eb234600d..b1ebcdaa7 100644 --- a/pkg/modules/auth/openid/openid_test.go +++ b/pkg/modules/auth/openid/openid_test.go @@ -128,8 +128,41 @@ func TestGetOrCreateUser(t *testing.T) { "email": cl.Email, }, false) db.AssertExists(t, "teams", map[string]interface{}{ - "id": oidcTeams, - "name": team + " (OIDC)", + "id": oidcTeams, + "name": team + " (OIDC)", + "is_public": false, + }, false) + }) + + t.Run("Update IsPublic flag for existing team", func(t *testing.T) { + db.LoadAndAssertFixtures(t) + s := db.NewSession() + defer s.Close() + + team := "testteam15" + oidcID := "15" + cl := &claims{ + Email: "other-email-address@some.service.com", + VikunjaGroups: []map[string]interface{}{ + {"name": team, "oidcID": oidcID, "isPublic": true}, + }, + } + + u, err := getOrCreateUser(s, cl, "https://some.service.com", "12345") + require.NoError(t, err) + teamData, errs := getTeamDataFromToken(cl.VikunjaGroups, nil) + for _, err := range errs { + require.NoError(t, err) + } + oidcTeams, err := AssignOrCreateUserToTeams(s, u, teamData, "https://some.issuer") + require.NoError(t, err) + err = s.Commit() + require.NoError(t, err) + + db.AssertExists(t, "teams", map[string]interface{}{ + "id": oidcTeams, + "name": team + " (OIDC)", + "is_public": true, }, false) }) diff --git a/pkg/routes/api/v1/info.go b/pkg/routes/api/v1/info.go index 59958b0dc..8bd16e76b 100644 --- a/pkg/routes/api/v1/info.go +++ b/pkg/routes/api/v1/info.go @@ -51,6 +51,7 @@ type vikunjaInfos struct { TaskCommentsEnabled bool `json:"task_comments_enabled"` DemoModeEnabled bool `json:"demo_mode_enabled"` WebhooksEnabled bool `json:"webhooks_enabled"` + PublicTeamsEnabled bool `json:"public_teams_enabled"` } type authInfo struct { @@ -95,6 +96,7 @@ func Info(c echo.Context) error { TaskCommentsEnabled: config.ServiceEnableTaskComments.GetBool(), DemoModeEnabled: config.ServiceDemoMode.GetBool(), WebhooksEnabled: config.WebhooksEnabled.GetBool(), + PublicTeamsEnabled: config.ServiceEnablePublicTeams.GetBool(), AvailableMigrators: []string{ (&vikunja_file.FileMigrator{}).Name(), (&ticktick.Migrator{}).Name(), diff --git a/pkg/swagger/docs.go b/pkg/swagger/docs.go index 76a185175..b67243664 100644 --- a/pkg/swagger/docs.go +++ b/pkg/swagger/docs.go @@ -8229,6 +8229,14 @@ const docTemplate = `{ "description": "The unique, numeric id of this team.", "type": "integer" }, + "include_public": { + "description": "Query parameter controlling whether to include public projects or not", + "type": "boolean" + }, + "is_public": { + "description": "Defines wether the team should be publicly discoverable when sharing a project", + "type": "boolean" + }, "members": { "description": "An array of all members in this team.", "type": "array", @@ -8364,6 +8372,14 @@ const docTemplate = `{ "description": "The unique, numeric id of this team.", "type": "integer" }, + "include_public": { + "description": "Query parameter controlling whether to include public projects or not", + "type": "boolean" + }, + "is_public": { + "description": "Defines wether the team should be publicly discoverable when sharing a project", + "type": "boolean" + }, "members": { "description": "An array of all members in this team.", "type": "array", @@ -8886,6 +8902,9 @@ const docTemplate = `{ "motd": { "type": "string" }, + "public_teams_enabled": { + "type": "boolean" + }, "registration_enabled": { "type": "boolean" }, diff --git a/pkg/swagger/swagger.json b/pkg/swagger/swagger.json index 7edf42ae0..836a1baa4 100644 --- a/pkg/swagger/swagger.json +++ b/pkg/swagger/swagger.json @@ -8221,6 +8221,14 @@ "description": "The unique, numeric id of this team.", "type": "integer" }, + "include_public": { + "description": "Query parameter controlling whether to include public projects or not", + "type": "boolean" + }, + "is_public": { + "description": "Defines wether the team should be publicly discoverable when sharing a project", + "type": "boolean" + }, "members": { "description": "An array of all members in this team.", "type": "array", @@ -8356,6 +8364,14 @@ "description": "The unique, numeric id of this team.", "type": "integer" }, + "include_public": { + "description": "Query parameter controlling whether to include public projects or not", + "type": "boolean" + }, + "is_public": { + "description": "Defines wether the team should be publicly discoverable when sharing a project", + "type": "boolean" + }, "members": { "description": "An array of all members in this team.", "type": "array", @@ -8878,6 +8894,9 @@ "motd": { "type": "string" }, + "public_teams_enabled": { + "type": "boolean" + }, "registration_enabled": { "type": "boolean" }, diff --git a/pkg/swagger/swagger.yaml b/pkg/swagger/swagger.yaml index 76a301bc3..1365bd24d 100644 --- a/pkg/swagger/swagger.yaml +++ b/pkg/swagger/swagger.yaml @@ -877,6 +877,14 @@ definitions: id: description: The unique, numeric id of this team. type: integer + include_public: + description: Query parameter controlling whether to include public projects + or not + type: boolean + is_public: + description: Defines wether the team should be publicly discoverable when + sharing a project + type: boolean members: description: An array of all members in this team. items: @@ -984,6 +992,14 @@ definitions: id: description: The unique, numeric id of this team. type: integer + include_public: + description: Query parameter controlling whether to include public projects + or not + type: boolean + is_public: + description: Defines wether the team should be publicly discoverable when + sharing a project + type: boolean members: description: An array of all members in this team. items: @@ -1369,6 +1385,8 @@ definitions: type: string motd: type: string + public_teams_enabled: + type: boolean registration_enabled: type: boolean task_attachments_enabled: