@@ -54,17 +43,14 @@
@@ -139,7 +89,7 @@ export default defineComponent({
display: flex;
flex-direction: column;
gap: 16px;
- max-width: 320px;
+ max-width: 400px;
}
.circle-config {
diff --git a/src/components/JoinInvitation.vue b/src/components/JoinInvitation.vue
new file mode 100644
index 000000000..d1e77b757
--- /dev/null
+++ b/src/components/JoinInvitation.vue
@@ -0,0 +1,127 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ t('contacts', 'Go to circle page') }}
+
+
+
+
+
+
+
+
+
+
+ {{ t('contacts', 'Go back') }}
+
+
+
+
+
+
+
+
+
+
+ {{ t('contacts', 'Join') }}
+
+
+ {{ t('contacts', 'Go back') }}
+
+
+
+
+
+
+
+
+
diff --git a/src/join-invitation.js b/src/join-invitation.js
new file mode 100644
index 000000000..28086ea50
--- /dev/null
+++ b/src/join-invitation.js
@@ -0,0 +1,18 @@
+/**
+ * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import { createApp } from 'vue'
+import JoinInvitation from './components/JoinInvitation.vue'
+import LegacyGlobalMixin from './mixins/LegacyGlobalMixin.js'
+
+import 'vite/modulepreload-polyfill'
+
+document.addEventListener('DOMContentLoaded', main)
+
+function main() {
+ const app = createApp(JoinInvitation)
+ app.mixin(LegacyGlobalMixin)
+ app.mount('#join-invitation')
+}
diff --git a/src/models/circle.ts b/src/models/circle.ts
index 5dae65dac..e6ab0e642 100644
--- a/src/models/circle.ts
+++ b/src/models/circle.ts
@@ -292,6 +292,14 @@ export default class Circle {
|| (this.config & CircleConfigs.FRIEND) !== 0
}
+ get invitationCode() {
+ return this._data.invitationCode
+ }
+
+ set invitationCode(invitationCode: string) {
+ this._data.invitationCode = invitationCode
+ }
+
// PARAMS ---------------------------------------------
/**
* Vue router param
diff --git a/src/models/constants.ts b/src/models/constants.ts
index 4da974e51..481ef2f8d 100644
--- a/src/models/constants.ts
+++ b/src/models/constants.ts
@@ -6,6 +6,8 @@
import { translate as t } from '@nextcloud/l10n'
import { ShareType } from '@nextcloud/sharing'
+import CircleConfigCheckboxesList from '../components/CircleDetails/CircleConfigs/CircleConfigCheckboxesList.vue'
+import CircleConfigInvitationLink from '../components/CircleDetails/CircleConfigs/CircleConfigInvitationLink.vue'
export type DefaultGroup = string
export type DefaultChart = string
@@ -92,20 +94,41 @@ export const CIRCLES_MEMBER_LEVELS = {
// Available circle configs in the circle details view
export const PUBLIC_CIRCLE_CONFIG = {
[t('contacts', 'Invites')]: {
- [CIRCLE_CONFIG_OPEN]: t('contacts', 'Anyone can request membership'),
- [CIRCLE_CONFIG_INVITE]: t('contacts', 'Members need to accept invitation'),
- [CIRCLE_CONFIG_REQUEST]: t('contacts', 'Memberships must be confirmed/accepted by a Moderator (requires "Anyone can request membership")'),
- [CIRCLE_CONFIG_FRIEND]: t('contacts', 'Members can also invite'),
+ component: CircleConfigCheckboxesList,
+ props: {
+ configs: {
+ [CIRCLE_CONFIG_OPEN]: t('contacts', 'Anyone can request membership'),
+ [CIRCLE_CONFIG_INVITE]: t('contacts', 'Members need to accept invitation'),
+ [CIRCLE_CONFIG_REQUEST]: t('contacts', 'Memberships must be confirmed/accepted by a Moderator (requires "Anyone can request membership")'),
+ [CIRCLE_CONFIG_FRIEND]: t('contacts', 'Members can also invite'),
+ },
+ },
+ },
+
+ [t('contacts', 'Invitation links')]: {
+ component: CircleConfigInvitationLink,
+ props: {},
},
[t('contacts', 'Membership')]: {
- // TODO: implement backend
- // [CIRCLE_CONFIG_CIRCLE_INVITE]: t('contacts', 'Team must confirm when invited in another circle'),
- [CIRCLE_CONFIG_ROOT]: t('contacts', 'Prevent teams from being a member of another team'),
+ component: CircleConfigCheckboxesList,
+ props: {
+ configs: {
+
+ // TODO: implement backend
+ // [CIRCLE_CONFIG_CIRCLE_INVITE]: t('contacts', 'Team must confirm when invited in another circle'),
+ [CIRCLE_CONFIG_ROOT]: t('contacts', 'Prevent teams from being a member of another team'),
+ },
+ },
},
[t('contacts', 'Privacy')]: {
- [CIRCLE_CONFIG_VISIBLE]: t('contacts', 'Visible to everyone'),
+ component: CircleConfigCheckboxesList,
+ props: {
+ configs: {
+ [CIRCLE_CONFIG_VISIBLE]: t('contacts', 'Visible to everyone'),
+ },
+ },
},
}
diff --git a/src/services/circles.ts b/src/services/circles.ts
index d833200f5..7fb02d624 100644
--- a/src/services/circles.ts
+++ b/src/services/circles.ts
@@ -47,6 +47,28 @@ export async function getCircle(circleId: string) {
return response.data.ocs.data
}
+/**
+ * Get a specific invitation
+ *
+ * @param invitationCode
+ * @return
+ */
+export async function getInvitation(invitationCode: string) {
+ const response = await axios.get(generateOcsUrl('apps/circles/invitations/{invitationCode}', { invitationCode }))
+ return response.data.ocs.data
+}
+
+/**
+ * Join to a circle using an invitation
+ *
+ * @param invitationCode
+ * @return
+ */
+export async function joinInvitation(invitationCode: string) {
+ const response = await axios.post(generateOcsUrl('apps/circles/invitations/{invitationCode}', { invitationCode }))
+ return response.data.ocs.data
+}
+
/**
* Create a new circle
*
@@ -197,3 +219,12 @@ export async function editCircleSetting(circleId: string, setting: CircleSetting
)
return response.data.ocs.data
}
+
+export async function createInvitationLink(circleId: string) {
+ const response = await axios.put(generateOcsUrl('apps/circles/circles/{circleId}/invitation', { circleId }))
+ return response.data.ocs.data
+}
+export async function revokeInvitationLink(circleId: string) {
+ const response = await axios.delete(generateOcsUrl('apps/circles/circles/{circleId}/invitation', { circleId }))
+ return response.data.ocs.data
+}
diff --git a/src/store/circles.js b/src/store/circles.js
index 3107482f8..27373dad5 100644
--- a/src/store/circles.js
+++ b/src/store/circles.js
@@ -10,6 +10,7 @@ import {
acceptMember,
addMembers,
createCircle,
+ createInvitationLink,
deleteCircle,
deleteMember,
editCircleSetting,
@@ -17,6 +18,7 @@ import {
getCircleMembers,
getCircles,
leaveCircle,
+ revokeInvitationLink,
} from '../services/circles.ts'
import logger from '../services/logger.js'
@@ -91,6 +93,10 @@ const mutations = {
setCircleSettings(state, { circleId, settings }) {
state.circles[circleId]._data.settings = settings
},
+
+ setInvitationCode(state, { circleId, invitationCode }) {
+ state.circles[circleId]._data.invitationCode = invitationCode
+ },
}
const getters = {
@@ -277,6 +283,21 @@ const actions = {
})
},
+ async createInvitationLink(context, { circleId }) {
+ const { invitationCode } = await createInvitationLink(circleId)
+ await context.commit('setInvitationCode', {
+ circleId,
+ invitationCode,
+ })
+ },
+
+ async revokeInvitationLink(context, { circleId }) {
+ const { invitationCode } = await revokeInvitationLink(circleId)
+ await context.commit('setInvitationCode', {
+ circleId,
+ invitationCode,
+ })
+ },
}
export default { state, mutations, getters, actions }
diff --git a/templates/join-invitation.php b/templates/join-invitation.php
new file mode 100644
index 000000000..697894c46
--- /dev/null
+++ b/templates/join-invitation.php
@@ -0,0 +1,10 @@
+
+
+
diff --git a/vite.config.js b/vite.config.js
index 7aeb675d2..db8c8a0f4 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -10,6 +10,7 @@ export default createAppConfig({
'main': path.join(__dirname, 'src', 'main.js'),
'files-action': path.join(__dirname, 'src', 'files-action.js'),
'admin-settings': path.join(__dirname, 'src', 'admin-settings.js'),
+ 'join-invitation': path.join(__dirname, 'src', 'join-invitation.js'),
'oca': path.join(__dirname, 'src', 'oca.ts'),
}, {
inlineCSS: false,