Skip to content

Commit

Permalink
fixup! feat: mail snippets
Browse files Browse the repository at this point in the history
Signed-off-by: Hamza Mahjoubi <[email protected]>
  • Loading branch information
hamza221 committed Oct 30, 2024
1 parent 8ea63b7 commit 05fa1b7
Show file tree
Hide file tree
Showing 14 changed files with 322 additions and 26 deletions.
40 changes: 40 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,46 @@
'url' => '/api/follow-up/check-message-ids',
'verb' => 'POST',
],
[
'name' => 'snippet#getOwnSnippets',
'url' => '/api/snippets',
'verb' => 'GET',
],
[
'name' => 'snippet#getSharedSnippets',
'url' => '/api/snippets/share',
'verb' => 'GET',
],
[
'name' => 'snippet#getShares',
'url' => '/api/snippets/share/shares',
'verb' => 'GET',
],
[
'name' => 'snippet#create',
'url' => '/api/snippets',
'verb' => 'POST',
],
[
'name' => 'snippet#update',
'url' => '/api/snippets',
'verb' => 'PUT',
],
[
'name' => 'snippet#delete',
'url' => '/api/snippets',
'verb' => 'DELETE',
],
[
'name' => 'snippet#share',
'url' => '/api/snippets/share',
'verb' => 'POST',
],
[
'name' => 'snippet#deleteShare',
'url' => '/api/snippets/share',
'verb' => 'DELETE',
],
],
'resources' => [
'accounts' => ['url' => '/api/accounts'],
Expand Down
50 changes: 50 additions & 0 deletions lib/Controller/SnippetController.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use OCA\Mail\Http\TrapError;
use OCA\Mail\Service\SnippetService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\IRequest;
Expand Down Expand Up @@ -96,7 +97,24 @@ public function update(int $snippetId, string $title, string $content): JsonResp
return JsonResponse::success($snippet, Http::STATUS_OK);
}

public function delete($snippetId): JsonResponse {
try {
$this->snippetService->delete($snippetId, $this->uid);
return JsonResponse::success();
} catch (DoesNotExistException $e) {
return JsonResponse::fail('Snippet not found', Http::STATUS_NOT_FOUND);
}
}

/**
* @NoAdminRequired
* @param int $snippetId
* @param string $shareWith
* @param string $type
*
* @return JsonResponse
*/
#[TrapError]
public function share(int $snippetId, string $shareWith, string $type): JsonResponse {
$snippet = $this->snippetService->find($snippetId, $this->uid);

Expand All @@ -117,4 +135,36 @@ public function share(int $snippetId, string $shareWith, string $type): JsonResp

}

public function getShares($id): JsonResponse {
$snippet = $this->snippetService->find($snippetId, $this->uid);

if ($snippet === null) {
return JsonResponse::error('Snippet not found', Http::STATUS_NOT_FOUND);
}

$shares = $this->snippetService->getShares($this->uid, $snippetId);

return JsonResponse::success($shares);
}

/**
* @NoAdminRequired
* @param int $snippetId
* @param string $shareWith
*
* @return JsonResponse
*/
#[TrapError]
public function deleteShare(int $snippetId, string $shareWith): JsonResponse {
$snippet = $this->snippetService->find($snippetId, $this->uid);

if ($snippet === null) {
return JsonResponse::error('Snippet not found', Http::STATUS_NOT_FOUND);
}

$this->snippetService->unshare($snippetId, $shareWith);

return JsonResponse::success();
}

}
4 changes: 2 additions & 2 deletions lib/Db/SnippetShareMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,15 @@ public function findAllShares(string $owner): array {
*
* @return SnippetShare[]
*/
public function findSnippetShares(string $owner, string $snippetId): array {
public function findSnippetShares(string $owner, int $snippetId): array {
$qb = $this->db->getQueryBuilder();
$qb->select('sshare.*')
->from($this->getTableName(), 'sshare')
->where(
$qb->expr()->eq('s.owner', $qb->createNamedParameter($owner, IQueryBuilder::PARAM_STR))
)
->andWhere(
$qb->expr()->eq('sshare.snippet_id', $qb->createNamedParameter($snippetId, IQueryBuilder::PARAM_STR))
$qb->expr()->eq('sshare.snippet_id', $qb->createNamedParameter($snippetId, IQueryBuilder::PARAM_INT))
);

return $this->findEntities($qb);
Expand Down
26 changes: 24 additions & 2 deletions lib/Service/SnippetService.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@ public function findAll(string $userId): array {

/**
* @param string
* @return Snippet[]
*/
public function findAllSharedWithMe(string $userId): array {
$groups = $this->groupManager->getUserGroupIds($userId);
return $this->snippetShareMapper->findSharedWithMe($userId, $groups);
return $this->snippetMapper->findSharedWithMe($userId, $groups);
}
/**
* @param int $snippetId
Expand Down Expand Up @@ -103,7 +104,13 @@ public function delete(int $snippetId, string $userId): void {
$this->snippetMapper->delete($snippet);
}

//TODO: run owner check on controller level

/**
* @param int $snippetId
* @param string $shareWith
* @throws DoesNotExistException
* @throws NotPermittedException
*/
public function share(int $snippetId, string $shareWith): void {

$sharee = $this->userManager->get($shareWith);
Expand All @@ -120,6 +127,16 @@ public function share(int $snippetId, string $shareWith): void {
$this->snippetShareMapper->insert($share);
}

public function getShares(string $uid, int $snippetId): array {
return $this->snippetShareMapper->findSnippetShares($uid, $snippetId);
}

/**
* @param int $snippetId
* @param string $groupId
* @throws DoesNotExistException
* @throws NotPermittedException
*/
public function shareWithGroup(int $snippetId, string $groupId): void {
if (!$this->groupManager->groupExists($groupId)) {
throw new DoesNotExistException('Group does not exist');
Expand All @@ -134,6 +151,11 @@ public function shareWithGroup(int $snippetId, string $groupId): void {
$this->snippetShareMapper->insert($share);
}

/**
* @param int $snippetId
* @param string $shareWith
* @throws DoesNotExistException
*/
public function unshare(int $snippetId, string $shareWith): void {
$share = $this->snippetShareMapper->find($snippetId, $shareWith);
$this->snippetShareMapper->delete($share);
Expand Down
15 changes: 11 additions & 4 deletions src/components/AppSettingsMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,10 @@
</NcAppSettingsSection>
<NcAppSettingsSection id="snippets" :name="t('mail', 'Snippets')">
<h6>{{ t('mail','My snippets') }}</h6>
<ListItem />
<List snippets="mySnippets" />
<h6>{{ t('mail','Shared with me') }}</h6>
<ListItem />
<List snippets="shareSnippet"
:shared="true" />
</NcAppSettingsSection>
</NcAppSettingsDialog>
</div>
Expand All @@ -319,7 +320,7 @@ import TrustedSenders from './TrustedSenders.vue'
import InternalAddress from './InternalAddress.vue'
import isMobile from '@nextcloud/vue/dist/Mixins/isMobile.js'
import { mapGetters } from 'vuex'
import ListItem from './snippets/ListItem.vue'
import List from './snippets/List.vue'

export default {
name: 'AppSettingsMenu',
Expand All @@ -338,7 +339,7 @@ export default {
CompactMode,
VerticalSplit,
HorizontalSplit,
ListItem,
List,
},
mixins: [isMobile],
props: {
Expand Down Expand Up @@ -407,6 +408,12 @@ export default {
layoutMode() {
return this.$store.getters.getPreference('layout-mode', 'vertical-split')
},
mySnippets() {
return this.$store.getters.getSnippets()
},
shareSnippet() {
return this.$store.getters.getSharedSnippets()
},
},
watch: {
showSettings(value) {
Expand Down
10 changes: 10 additions & 0 deletions src/components/Composer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@
:placeholder="t('mail', 'Write message …')"
:focus="isReply || !isFirstOpen"
:bus="bus"
:snippets="snippets"
@input="onEditorInput"
@ready="onEditorReady"
@mention="handleMention"
Expand Down Expand Up @@ -889,6 +890,11 @@ export default {

return missingCertificates
},

snippets() {
return this.$store.getters.getSharedSnippets.map(snippet => ({ title: snippet.title, content: snippet.content }))
.concat(this.$store.getters.getMySnippets.map(snippet => ({ title: snippet.title, content: snippet.content })))
},
},
watch: {
'$route.params.threadId'() {
Expand Down Expand Up @@ -987,6 +993,10 @@ export default {
if (this.sendAt && this.isSendAtCustom) {
this.selectedDate = new Date(this.sendAt)
}
if (this.snippets.length === 0) {
this.$store.dispatch('fetchSharedSnippets')
this.$store.dispatch('fetchMySnippets')
}
},
beforeDestroy() {
window.removeEventListener('mailvelope', this.onMailvelopeLoaded)
Expand Down
4 changes: 4 additions & 0 deletions src/components/TextEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ export default {
type: Boolean,
default: false,
},
snippets: {
type: Array,
default: () => [],
},
},
data() {
const plugins = [
Expand Down
22 changes: 14 additions & 8 deletions src/components/snippets/List.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,28 @@
- SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<div>
<ListItem v-for="snippet in snippets" :key="snippet.id" :snippet="snippet" />
<span v-if="!snippets.length"> {{ t('mail', 'No snippets available') }} </span>
</div>
</template>

<script>

import ListItem from './ListItem.vue'
export default {
name: 'List',
components: {

ListItem,
},
props: {
},
data() {
},
mounted() {
},
updated() {
shared: {
type: Boolean,
default: false,
},
snippets: {
type: Array,
required: true,
},
},
methods: {
},
Expand Down
27 changes: 17 additions & 10 deletions src/components/snippets/ListItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
{{ snippet.preview }}
</p>

<NcSelect v-model="snippet.sharedWith"
<NcSelect v-if="!shared"
class="snippet-list-item__shares"
:options="['hamzamahjoubi', 'user1', 'user2']"
@change="shareSnippet(snippet.id, snippet.sharedWith)" />
Expand All @@ -37,6 +37,7 @@

<script>
import { NcActions, NcActionButton, NcSelect, NcDialog, NcTextArea, NcInputField } from '@nextcloud/vue'
import { getShares } from '../../service/SnippetService.js'
import IconCancel from '@mdi/svg/svg/cancel.svg?raw'
import IconCheck from '@mdi/svg/svg/check.svg?raw'

Expand All @@ -51,16 +52,19 @@ export default {
NcInputField,
},
props: {
snippet: {
type: Object,
required: true,
},
shared: {
type: Boolean,
default: false,
},
},
data() {
return {
snippet: { // snippet is not defined
id: 1,
title: 'This is a title',
preview: 'This is a preview',
shared: false,
sharedWith: 'hamzamahjoubi',
},
shares: null,
localSnippet: Object.assign({}, this.snippet),
editModalOpen: false,
buttons: [
{
Expand All @@ -72,12 +76,15 @@ export default {
label: 'Ok',
type: 'primary',
icon: IconCheck,
callback: () => { console.log('Pressed "Ok"') },
callback: () => { this.$store.dispatch('patchSnippet', this.localSnippet) },
},
],
}
},
mounted() {
async mounted() {
if (!this.shared) {
this.shares = await getShares()
}
},
updated() {
},
Expand Down
Loading

0 comments on commit 05fa1b7

Please sign in to comment.