Skip to content

Commit

Permalink
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 17, 2024
1 parent 3c4caff commit 24e8b38
Show file tree
Hide file tree
Showing 10 changed files with 496 additions and 1 deletion.
2 changes: 1 addition & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ The rating depends on the installed text processing backend. See [the rating ove
Learn more about the Nextcloud Ethical AI Rating [in our blog](https://nextcloud.com/blog/nextcloud-ethical-ai-rating/).
]]></description>
<version>4.1.0-alpha.2</version>
<version>4.1.0-alpha.4</version>
<licence>agpl</licence>
<author homepage="https://github.com/ChristophWurst">Christoph Wurst</author>
<author homepage="https://github.com/GretaD">GretaD</author>
Expand Down
44 changes: 44 additions & 0 deletions lib/Db/Snippet.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Mail\Db;

use JsonSerializable;
use OCP\AppFramework\Db\Entity;
use ReturnTypeWillChange;

/**
* @method string getOwner()
* @method void setOwner(string $owner)
* @method string geTitle()
* @method void setTitle(string $title)
* @method string getContent()
* @method void setContent(string $content)
*/
class Snippet extends Entity implements JsonSerializable {
protected $owner;
protected $title;
protected $content;

public function __construct() {
$this->addType('owner', 'string');
$this->addType('title', 'string');
$this->addType('content', 'string');
}

#[ReturnTypeWillChange]
public function jsonSerialize() {
return [
'id' => $this->getId(),
'owner' => $this->getOwner(),
'title' => $this->geTitle(),
'content' => $this->getContent(),
];
}
}
82 changes: 82 additions & 0 deletions lib/Db/SnippetMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Mail\Db;

use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;

/**
* @template-extends QBMapper<Snippet>
*/
class SnippetMapper extends QBMapper {
/**
* @param IDBConnection $db
*/
public function __construct(IDBConnection $db) {
parent::__construct($db, 'mail_snippets');
}

/**
* @param int $id
* @param string $owner
* @return Snippet
*
* @throws DoesNotExistException
*/
public function find(int $id, string $owner): Snippet {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
->andWhere($qb->expr()->eq('owner', $qb->createNamedParameter($owner)));

return $this->findEntity($qb);
}

/**
* @param string $owner
* @return Snippet[]
*/
public function findAll(string $owner): array {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->where(
$qb->expr()->eq('owner', $qb->createNamedParameter($owner, IQueryBuilder::PARAM_STR))
);

return $this->findEntities($qb);
}

/**
* @param string $userId
* @param array $groups
* @return Snippet[]
*/
public function findSharedWithMe(string $userId, array $groups): array {
$qb = $this->db->getQueryBuilder();
$qb->select('s.*')
->from($this->getTableName(), 's')
->join('s', 'mail_snippets_shares', 'share', $qb->expr()->eq('s.id', 'sshare.snippet_id'))
->where($qb->expr()->andX(
$qb->expr()->eq('sshare.share_with', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)),
$qb->expr()->in('sshare.type', $qb->createNamedParameter('user', IQueryBuilder::PARAM_STR))
))
->orWhere(
$qb->expr()->andX(
$qb->expr()->in('sshare.share_with', $qb->createNamedParameter($groups, IQueryBuilder::PARAM_STR_ARRAY)),
$qb->expr()->in('sshare.type', $qb->createNamedParameter('group', IQueryBuilder::PARAM_STR))
)
);
return $this->findEntities($qb);
}
}
44 changes: 44 additions & 0 deletions lib/Db/SnippetShare.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Mail\Db;

use JsonSerializable;
use OCP\AppFramework\Db\Entity;
use ReturnTypeWillChange;

/**
* @method string getType()
* @method void setType(string $type)
* @method string getShareWith()
* @method void setShareWith((string $shareWith)
* @method string getSnippetId()
* @method void setSnippetId(string $snippetId)
*/
class SnippetShare extends Entity implements JsonSerializable {

Check failure on line 24 in lib/Db/SnippetShare.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

InvalidDocblock

lib/Db/SnippetShare.php:24:7: InvalidDocblock: Badly-formatted @method string setShareWith((string $shareWith) - Psalm\Exception\TypeParseTreeException: Unterminated parentheses in phar:///home/runner/actions-runner/_work/mail/mail/vendor/psalm/phar/psalm.phar/src/Psalm/Internal/Type/TypeParser.php:174 Stack trace: #0 phar:///home/runner/actions-runner/_work/mail/mail/vendor/psalm/phar/psalm.phar/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeDocblockParser.php(280): Psalm\Internal\Type\TypeParser::getTypeFromTree(Object(Psalm\Internal\Type\ParseTree\EncapsulationTree), Object(Psalm\Codebase)) #1 phar:///home/runner/actions-runner/_work/mail/mail/vendor/psalm/phar/psalm.phar/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php(277): Psalm\Internal\PhpVisitor\Reflector\ClassLikeDocblockParser::parse(Object(_HumbugBox7ff99e199a36\PhpParser\Node\Stmt\Class_), Object(_HumbugBox7ff99e199a36\PhpParser\Comment\Doc), Object(Psalm\Aliases)) #2 phar:///home/runner/actions-runner/_work/mail/mail/vendor/psalm/phar/psalm.phar/src/Psalm/Internal/PhpVisitor/ReflectorVisitor.php(116): Psalm\Internal\PhpVisitor\Reflector\ClassLikeNodeScanner->start(Object(_HumbugBox7ff99e199a36\PhpParser\Node\Stmt\Class_)) #3 phar:///home/runner/actions-runner/_work/mail/mail/vendor/psalm/phar/psalm.phar/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(176): Psalm\Internal\PhpVisitor\ReflectorVisitor->enterNode(Object(_HumbugBox7ff99e199a36\PhpParser\Node\Stmt\Class_)) #4 phar:///home/runner/actions-runner/_work/mail/mail/vendor/psalm/phar/psalm.phar/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(105): _HumbugBox7ff99e199a36\PhpParser\NodeTraverser->traverseArray(Array) #5 phar:///home/runner/actions-runner/_work/mail/mail/vendor/psalm/phar/psalm.phar/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(196): _HumbugBox7ff99e199a36\PhpParser\NodeTraverser->traverseNode(Object(_HumbugBox7ff99e199a36\PhpParser\Node\Stmt\Namespace_)) #6 phar:///home/runner/actions-runner/_work/mail/mail/vendor/psalm/phar/psalm.phar/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(85): _HumbugBox7ff99e199a36\PhpParser\NodeTraverser->traverseArray(Array) #7 phar:///home/runner/actions-runner/_work/mail/mail/vendor/psalm/phar/psalm.phar/src/Psalm/Internal/Scanner/FileScanner.php(51): _HumbugBox7ff99e199a36\PhpParser\NodeTraverser->traverse(Array) #8 phar:///home/runner/actions-runner/_work/mail/mail/vendor/psalm/phar/psalm.phar/src/Psalm/Internal/Codebase/Scanner.php(395): Psalm\Internal\Scanner\FileScanner->scan(Object(Psalm\Codebase), Object(Psalm\Storage\FileStorage), false, Object(Psalm\Progress\LongProgress)) #9 phar:///home/runner/actions-runner/_work/mail/mail/vendor/psalm/phar/psalm.phar/src/Psalm/Internal/Codebase/Scanner.php(544): Psalm\Internal\Codebase\Scanner->scanFile('/home/runner/ac...', Array, true) #10 phar:///home/runner/actions-runner/_work/mail/mail/vendor/psalm/phar/psalm.phar/src/Psalm/Internal/Codebase/Scanner.php(307): Psalm\Internal\Codebase\Scanner->scanAPath(3087, '/home/runner/ac...') #11 phar:///home/runner/actions-runner/_work/mail/mail/vendor/psalm/phar/psalm.phar/src/Psalm/Internal/Codebase/Scanner.php(220): Psalm\Internal\Codebase\Scanner->scanFilePaths(1) #12 phar:///home/runner/actions-runner/_work/mail/mail/vendor/psalm/phar/psalm.phar/src/Psalm/Codebase.php(385): Psalm\Internal\Codebase\Scanner->scanFiles(Object(Psalm\Internal\Codebase\ClassLikes), 1) #13 phar:///home/runner/actions-runner/_work/mail/mail/vendor/psalm/phar/psalm.phar/src/Psalm/Internal/Analyzer/ProjectAnalyzer.php(340): Psalm\Codebase->scanFiles(1) #14 phar:///home/runner/actions-runner/_work/mail/mail/vendor/psalm/phar/psalm.phar/src/Psalm/Internal/Cli/Psalm.php(278): Psalm\Internal\Analyzer\ProjectAnalyzer->check('/home/runner/ac...', true) #15 phar:///home/runner/actions-runner/_work/mail/mail/vendor/psalm/phar/psalm.phar/psalm(7): Psalm\Internal\Cli\Psalm::run(Array) #16 /home/runner/actions-runner/_work/mail/mail/vendor/psalm/phar/psalm.phar(14): require('phar:///home/ru...') #17 /home/runner/actions-runner/_work/mail/mail/vendo
protected $owner;
protected $title;
protected $content;

public function __construct() {
$this->addType('type', 'string');
$this->addType('shareWith', 'string');
$this->addType('snippetId', 'string');
}

#[ReturnTypeWillChange]
public function jsonSerialize() {
return [
'id' => $this->getId(),
'type' => $this->getType(),

Check failure on line 39 in lib/Db/SnippetShare.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

UndefinedMagicMethod

lib/Db/SnippetShare.php:39:21: UndefinedMagicMethod: Magic method OCA\Mail\Db\SnippetShare::gettype does not exist (see https://psalm.dev/219)
'shareWith' => $this->getShareWith(),

Check failure on line 40 in lib/Db/SnippetShare.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

UndefinedMagicMethod

lib/Db/SnippetShare.php:40:26: UndefinedMagicMethod: Magic method OCA\Mail\Db\SnippetShare::getsharewith does not exist (see https://psalm.dev/219)
'snippetId' => $this->getSnippetId(),

Check failure on line 41 in lib/Db/SnippetShare.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

UndefinedMagicMethod

lib/Db/SnippetShare.php:41:26: UndefinedMagicMethod: Magic method OCA\Mail\Db\SnippetShare::getsnippetid does not exist (see https://psalm.dev/219)
];
}
}
82 changes: 82 additions & 0 deletions lib/Db/SnippetShareMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Mail\Db;

use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;

/**
* @template-extends QBMapper<SnippetShare>
*/
class SnippetShareMapper extends QBMapper {
/**
* @param IDBConnection $db
*/
public function __construct(IDBConnection $db) {
parent::__construct($db, 'mail_snippets_shares');
}

/**
* @param int $id
* @param string $owner
* @return Snippet

Check failure on line 31 in lib/Db/SnippetShareMapper.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

InvalidReturnType

lib/Db/SnippetShareMapper.php:31:13: InvalidReturnType: The declared return type 'OCA\Mail\Db\Snippet' for OCA\Mail\Db\SnippetShareMapper::find is incorrect, got 'OCA\Mail\Db\SnippetShare' (see https://psalm.dev/011)
*
* @throws DoesNotExistException
*/
public function find(int $id, string $owner): Snippet {
$qb = $this->db->getQueryBuilder();
$qb->select('*')
->from($this->getTableName())
->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
->andWhere($qb->expr()->eq('owner', $qb->createNamedParameter($owner)));

return $this->findEntity($qb);

Check failure on line 42 in lib/Db/SnippetShareMapper.php

View workflow job for this annotation

GitHub Actions / static-psalm-analysis dev-master

InvalidReturnStatement

lib/Db/SnippetShareMapper.php:42:10: InvalidReturnStatement: The inferred type 'OCA\Mail\Db\SnippetShare' does not match the declared return type 'OCA\Mail\Db\Snippet' for OCA\Mail\Db\SnippetShareMapper::find (see https://psalm.dev/128)
}

/**
* @param string $owner
* @return SnippetShare[]
*/
public function findAllShares(string $owner): array {
$qb = $this->db->getQueryBuilder();
$qb->select('sshare.*')
->from($this->getTableName(), 'sshare')
->join('sshare', 'mail_snippets', 's', $qb->expr()->eq('sshare.snippet_id', 's.id', IQueryBuilder::PARAM_INT))
->where(
$qb->expr()->eq('s.owner', $qb->createNamedParameter($owner, IQueryBuilder::PARAM_STR))
);

return $this->findEntities($qb);
}

/**
* @param string $owner
* @param string $snippetId
*
* @return SnippetShare[]
*/
public function findSnippetShares(string $owner, string $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))
);

return $this->findEntities($qb);
}


}
50 changes: 50 additions & 0 deletions lib/Migration/Version4001Date20241017154801.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Mail\Migration;

use Closure;
use OCP\DB\ISchemaWrapper;
use OCP\DB\Types;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;

class Version4001Date20241017154801 extends SimpleMigrationStep {
/**
* @param IOutput $output
* @param Closure(): ISchemaWrapper $schemaClosure
* @param array $options
* @return ISchemaWrapper
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
$table = $schema->createTable('mail_snippets');

$table->addColumn('id', Types::INTEGER, [
'autoincrement' => true,
'notnull' => true,
'length' => 4,
]);
$table->addColumn('owner', Types::STRING, [
'notnull' => true,
'length' => 64,
]);
$table->addColumn('title', Types::STRING, [
'notnull' => true,
'length' => 64,
]);
$table->addColumn('content', Types::TEXT, [
'notnull' => true,
]);
$table->setPrimaryKey(['id']);

return $schema;
}
}
50 changes: 50 additions & 0 deletions lib/Migration/Version4001Date20241017155914.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Mail\Migration;

use Closure;
use OCP\DB\ISchemaWrapper;
use OCP\DB\Types;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;

class Version4001Date20241017155914 extends SimpleMigrationStep {
/**
* @param IOutput $output
* @param Closure(): ISchemaWrapper $schemaClosure
* @param array $options
* @return ISchemaWrapper
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
$table = $schema->createTable('mail_snippets_shares');

$table->addColumn('id', Types::INTEGER, [
'autoincrement' => true,
'notnull' => true,
'length' => 4,
]);
$table->addColumn('type', Types::STRING, [
'notnull' => true,
'length' => 64,
]);
$table->addColumn('share_with', Types::STRING, [
'notnull' => true,
'length' => 64,
]);
$table->addColumn('snippet_id', Types::STRING, [
'notnull' => true,
'length' => 64,
]);
$table->setPrimaryKey(['id']);
return $schema;
}
}
8 changes: 8 additions & 0 deletions src/components/AppSettingsMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,12 @@
</div>
</dl>
</NcAppSettingsSection>
<NcAppSettingsSection id="snippets" :name="t('mail', 'Snippets')">
<h6>{{ t('mail','My snippets') }}</h6>
<ListItem />
<h6>{{ t('mail','Shared with me') }}</h6>
<ListItem />
</NcAppSettingsSection>
</NcAppSettingsDialog>
</div>
</template>
Expand All @@ -313,6 +319,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'
export default {
name: 'AppSettingsMenu',
Expand All @@ -331,6 +338,7 @@ export default {
CompactMode,
VerticalSplit,
HorizontalSplit,
ListItem,
},
mixins: [isMobile],
props: {
Expand Down
Loading

0 comments on commit 24e8b38

Please sign in to comment.