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 457c827 commit f2dd62e
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);

Check warning on line 97 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L97

Added line #L97 was not covered by tests
}

public function delete($snippetId): JsonResponse {

Check warning on line 100 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L100

Added line #L100 was not covered by tests
try {
$this->snippetService->delete($snippetId, $this->uid);

Check failure on line 102 in lib/Controller/SnippetController.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

PossiblyNullArgument

lib/Controller/SnippetController.php:102:46: PossiblyNullArgument: Argument 2 of OCA\Mail\Service\SnippetService::delete cannot be null, possibly null value provided (see https://psalm.dev/078)
return JsonResponse::success();
} catch (DoesNotExistException $e) {
return JsonResponse::fail('Snippet not found', Http::STATUS_NOT_FOUND);

Check warning on line 105 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L102-L105

Added lines #L102 - L105 were not covered by tests
}
}

/**
* @NoAdminRequired
* @param int $snippetId
* @param string $shareWith
* @param string $type
*
* @return JsonResponse
*/
#[TrapError]

Check warning on line 117 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L117

Added line #L117 was not covered by tests
public function share(int $snippetId, string $shareWith, string $type): JsonResponse {
$snippet = $this->snippetService->find($snippetId, $this->uid);

Check failure on line 119 in lib/Controller/SnippetController.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

PossiblyNullArgument

lib/Controller/SnippetController.php:119:54: PossiblyNullArgument: Argument 2 of OCA\Mail\Service\SnippetService::find cannot be null, possibly null value provided (see https://psalm.dev/078)

Check warning on line 119 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L119

Added line #L119 was not covered by tests

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);

Check failure on line 139 in lib/Controller/SnippetController.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

UndefinedVariable

lib/Controller/SnippetController.php:139:42: UndefinedVariable: Cannot find referenced variable $snippetId (see https://psalm.dev/024)

Check failure on line 139 in lib/Controller/SnippetController.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

PossiblyNullArgument

lib/Controller/SnippetController.php:139:54: PossiblyNullArgument: Argument 2 of OCA\Mail\Service\SnippetService::find cannot be null, possibly null value provided (see https://psalm.dev/078)

Check warning on line 139 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L138-L139

Added lines #L138 - L139 were not covered by tests

if ($snippet === null) {

Check failure on line 141 in lib/Controller/SnippetController.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

TypeDoesNotContainNull

lib/Controller/SnippetController.php:141:7: TypeDoesNotContainNull: OCA\Mail\Db\Snippet does not contain null (see https://psalm.dev/090)
return JsonResponse::error('Snippet not found', Http::STATUS_NOT_FOUND);

Check warning on line 142 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L141-L142

Added lines #L141 - L142 were not covered by tests
}

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

Check warning on line 145 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L145

Added line #L145 was not covered by tests

return JsonResponse::success($shares);

Check warning on line 147 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L147

Added line #L147 was not covered by tests
}

/**
* @NoAdminRequired
* @param int $snippetId
* @param string $shareWith
*
* @return JsonResponse
*/
#[TrapError]

Check warning on line 157 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L157

Added line #L157 was not covered by tests
public function deleteShare(int $snippetId, string $shareWith): JsonResponse {
$snippet = $this->snippetService->find($snippetId, $this->uid);

Check warning on line 159 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L159

Added line #L159 was not covered by tests

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

Check warning on line 162 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L161-L162

Added lines #L161 - L162 were not covered by tests
}

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

Check warning on line 165 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L165

Added line #L165 was not covered by tests

return JsonResponse::success();

Check warning on line 167 in lib/Controller/SnippetController.php

View check run for this annotation

Codecov / codecov/patch

lib/Controller/SnippetController.php#L167

Added line #L167 was not covered by tests
}

}
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))
);

Check warning on line 94 in lib/Db/SnippetShareMapper.php

View check run for this annotation

Codecov / codecov/patch

lib/Db/SnippetShareMapper.php#L85-L94

Added lines #L85 - L94 were not covered by tests

return $this->findEntities($qb);

Check warning on line 96 in lib/Db/SnippetShareMapper.php

View check run for this annotation

Codecov / codecov/patch

lib/Db/SnippetShareMapper.php#L96

Added line #L96 was not covered by tests
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);

Check warning on line 56 in lib/Service/SnippetService.php

View check run for this annotation

Codecov / codecov/patch

lib/Service/SnippetService.php#L54-L56

Added lines #L54 - L56 were not covered by tests
}
/**
* @param int $snippetId
Expand Down Expand Up @@ -103,7 +104,13 @@ public function delete(int $snippetId, string $userId): void {
$this->snippetMapper->delete($snippet);

Check warning on line 104 in lib/Service/SnippetService.php

View check run for this annotation

Codecov / codecov/patch

lib/Service/SnippetService.php#L102-L104

Added lines #L102 - L104 were not covered by tests
}

//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 {

Check warning on line 114 in lib/Service/SnippetService.php

View check run for this annotation

Codecov / codecov/patch

lib/Service/SnippetService.php#L114

Added line #L114 was not covered by tests

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

Check warning on line 127 in lib/Service/SnippetService.php

View check run for this annotation

Codecov / codecov/patch

lib/Service/SnippetService.php#L123-L127

Added lines #L123 - L127 were not covered by tests
}

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

Check warning on line 131 in lib/Service/SnippetService.php

View check run for this annotation

Codecov / codecov/patch

lib/Service/SnippetService.php#L130-L131

Added lines #L130 - L131 were not covered by tests
}

/**
* @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');

Check warning on line 142 in lib/Service/SnippetService.php

View check run for this annotation

Codecov / codecov/patch

lib/Service/SnippetService.php#L140-L142

Added lines #L140 - L142 were not covered by tests
Expand All @@ -134,6 +151,11 @@ public function shareWithGroup(int $snippetId, string $groupId): void {
$this->snippetShareMapper->insert($share);

Check warning on line 151 in lib/Service/SnippetService.php

View check run for this annotation

Codecov / codecov/patch

lib/Service/SnippetService.php#L147-L151

Added lines #L147 - L151 were not covered by tests
}

/**
* @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);

Check warning on line 161 in lib/Service/SnippetService.php

View check run for this annotation

Codecov / codecov/patch

lib/Service/SnippetService.php#L159-L161

Added lines #L159 - L161 were not covered by tests
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'

Check failure on line 41 in src/components/snippets/ListItem.vue

View workflow job for this annotation

GitHub Actions / NPM lint

Unable to resolve path to module '@mdi/svg/svg/cancel.svg?raw'
import IconCheck from '@mdi/svg/svg/check.svg?raw'

Check failure on line 42 in src/components/snippets/ListItem.vue

View workflow job for this annotation

GitHub Actions / NPM lint

Unable to resolve path to module '@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 f2dd62e

Please sign in to comment.