Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@
['name' => 'stack_ocs#create', 'url' => '/api/v{apiVersion}/stacks', 'verb' => 'POST'],
['name' => 'stack_ocs#delete', 'url' => '/api/v{apiVersion}/stacks/{stackId}/{boardId}', 'verb' => 'DELETE', 'defaults' => ['boardId' => null]],

['name' => 'attachment_ocs#getAll', 'url' => '/api/v{apiVersion}/cards/{cardId}/attachments', 'verb' => 'GET'],
['name' => 'attachment_ocs#create', 'url' => '/api/v{apiVersion}/cards/{cardId}/attachment', 'verb' => 'POST'],
['name' => 'attachment_ocs#update', 'url' => '/api/v{apiVersion}/cards/{cardId}/attachments/{attachmentId}', 'verb' => 'PUT'],
['name' => 'attachment_ocs#delete', 'url' => '/api/v{apiVersion}/cards/{cardId}/attachments/{attachmentId}', 'verb' => 'DELETE'],
['name' => 'attachment_ocs#restore', 'url' => '/api/v{apiVersion}/cards/{cardId}/attachments/{attachmentId}/restore', 'verb' => 'PUT'],

['name' => 'Config#get', 'url' => '/api/v{apiVersion}/config', 'verb' => 'GET'],
['name' => 'Config#setValue', 'url' => '/api/v{apiVersion}/config/{key}', 'verb' => 'POST'],

Expand Down
83 changes: 83 additions & 0 deletions lib/Controller/AttachmentOcsController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Deck\Controller;

use OCA\Deck\NotImplementedException;
use OCA\Deck\Service\AttachmentService;
use OCA\Deck\Service\BoardService;
use OCP\AppFramework\Http\Attribute\CORS;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\IRequest;

class AttachmentOcsController extends OCSController {
public function __construct(
string $appName,
IRequest $request,
private AttachmentService $attachmentService,
private BoardService $boardService,
) {
parent::__construct($appName, $request);
}

private function ensureLocalBoard(?int $boardId): void {
if ($boardId) {
$board = $this->boardService->find($boardId);
if ($board->getExternalId()) {
throw new NotImplementedException('attachments for federated boards are not supported');
}
}
}

#[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function getAll(int $cardId, ?int $boardId = null): DataResponse {
$this->ensureLocalBoard($boardId);
$attachment = $this->attachmentService->findAll($cardId, true);
return new DataResponse($attachment);
}

#[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function create(int $cardId, string $type, string $data = '', ?int $boardId = null): DataResponse {
$this->ensureLocalBoard($boardId);
$attachment = $this->attachmentService->create($cardId, $type, $data);
return new DataResponse($attachment);
}

#[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function update(int $cardId, int $attachmentId, string $data, string $type = 'file', ?int $boardId = null): DataResponse {
$this->ensureLocalBoard($boardId);
$attachment = $this->attachmentService->update($cardId, $attachmentId, $data, $type);
return new DataResponse($attachment);
}

#[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function delete(int $cardId, int $attachmentId, string $type = 'file', ?int $boardId = null): DataResponse {
$this->ensureLocalBoard($boardId);
$attachment = $this->attachmentService->delete($cardId, $attachmentId, $type);
return new DataResponse($attachment);
}

#[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function restore(int $cardId, int $attachmentId, string $type = 'file', ?int $boardId = null): DataResponse {
$this->ensureLocalBoard($boardId);
$attachment = $this->attachmentService->restore($cardId, $attachmentId, $type);
return new DataResponse($attachment);
}

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

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

namespace OCA\Deck;

use OCP\AppFramework\Http;

class NotImplementedException extends StatusException {
public function __construct($message) {
parent::__construct($message);
}

public function getStatus() {
return HTTP::STATUS_NOT_IMPLEMENTED;
}
}
2 changes: 1 addition & 1 deletion lib/Service/AttachmentService.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public function count(int $cardId): int {
* @throws StatusException
* @throws BadRequestException
*/
public function create(int $cardId, string $type, string $data) {
public function create(int $cardId, string $type, string $data = '') {
$this->attachmentServiceValidator->check(compact('cardId', 'type'));

$this->permissionService->checkPermission($this->cardMapper, $cardId, Acl::PERMISSION_EDIT);
Expand Down
56 changes: 34 additions & 22 deletions src/services/AttachmentApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,62 +4,74 @@
*/

import axios from '@nextcloud/axios'
import { generateUrl } from '@nextcloud/router'
import { generateOcsUrl, generateUrl } from '@nextcloud/router'

export class AttachmentApi {

url(url) {
return generateUrl(`/apps/deck${url}`)
}

async fetchAttachments(cardId) {
ocsUrl(url) {
url = `/apps/deck/api/v1.0${url}`
return generateOcsUrl(url)
}

async fetchAttachments(cardId, boardId) {
const response = await axios({
method: 'GET',
url: this.url(`/cards/${cardId}/attachments`),
url: this.ocsUrl(`/cards/${cardId}/attachments`),
params: {
boardId: boardId ?? null,
},
})
return response.data
return response.data.ocs.data
}

async createAttachment({ cardId, formData, onUploadProgress }) {
async createAttachment({ cardId, formData, onUploadProgress, boardId }) {
const response = await axios({
method: 'POST',
url: this.url(`/cards/${cardId}/attachment`),
url: this.ocsUrl(`/cards/${cardId}/attachment`),
params: {
boardId: boardId ?? null,
},
data: formData,
onUploadProgress,
})
return response.data
return response.data.ocs.data
}

async updateAttachment({ cardId, attachment, formData }) {
async updateAttachment({ cardId, attachment, formData, boardId }) {
const response = await axios({
method: 'POST',
url: this.url(`/cards/${cardId}/attachment/${attachment.type}:${attachment.id}`),
url: this.ocsUrl(`/cards/${cardId}/attachment/${attachment.type}:${attachment.id}`),
params: {
boardId: boardId ?? null,
},
data: formData,
})
return response.data
}

async deleteAttachment(attachment) {
async deleteAttachment(attachment, boardId) {
await axios({
method: 'DELETE',
url: this.url(`/cards/${attachment.cardId}/attachment/${attachment.type}:${attachment.id}`),
})
}

async restoreAttachment(attachment) {
const response = await axios({
method: 'GET',
url: this.url(`/cards/${attachment.cardId}/attachment/${attachment.type}:${attachment.id}/restore`),
url: this.ocsUrl(`/cards/${attachment.cardId}/attachment/${attachment.type}:${attachment.id}`),
params: {
boardId: boardId ?? null,
},
})
return response.data
}

async displayAttachment(attachment) {
async restoreAttachment(attachment, boardId) {
const response = await axios({
method: 'GET',
url: this.url(`/cards/${attachment.cardId}/attachment/${attachment.type}:${attachment.id}`),
url: this.ocsUrl(`/cards/${attachment.cardId}/attachment/${attachment.type}:${attachment.id}/restore`),
params: {
boardId: boardId ?? null,
},
})
return response.data
return response.data.ocs.data
}

}
30 changes: 18 additions & 12 deletions src/store/attachment.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,37 +64,43 @@ export default {

},
actions: {
async fetchAttachments({ commit }, cardId) {
const attachments = await apiClient.fetchAttachments(cardId)
async fetchAttachments({ commit, rootState }, cardId) {
const boardId = rootState.currentBoard.id
const attachments = await apiClient.fetchAttachments(cardId, boardId)
commit('createAttachments', { cardId, attachments })
commit('cardSetAttachmentCount', { cardId, count: attachments.length })
},

async createAttachment({ commit }, { cardId, formData, onUploadProgress }) {
const attachment = await apiClient.createAttachment({ cardId, formData, onUploadProgress })
async createAttachment({ commit, rootState }, { cardId, formData, onUploadProgress }) {
const boardId = rootState.currentBoard.id
const attachment = await apiClient.createAttachment({ cardId, formData, onUploadProgress, boardId })
commit('createAttachment', { cardId, attachment })
commit('cardIncreaseAttachmentCount', cardId)
},

async updateAttachment({ commit }, { cardId, attachment, formData }) {
const result = await apiClient.updateAttachment({ cardId, attachment, formData })
async updateAttachment({ commit, rootState }, { cardId, attachment, formData }) {
const boardId = rootState.currentBoard.id
const result = await apiClient.updateAttachment({ cardId, attachment, formData, boardId })
commit('updateAttachment', { cardId, attachment: result })
},

async deleteAttachment({ commit }, attachment) {
await apiClient.deleteAttachment(attachment)
async deleteAttachment({ commit, rootState }, attachment) {
const boardId = rootState.currentBoard.id
await apiClient.deleteAttachment(attachment, boardId)
commit('deleteAttachment', attachment)
commit('cardDecreaseAttachmentCount', attachment.cardId)
},

async unshareAttachment({ commit }, attachment) {
await apiClient.deleteAttachment(attachment)
async unshareAttachment({ commit, rootState }, attachment) {
const boardId = rootState.currentBoard.id
await apiClient.deleteAttachment(attachment, boardId)
commit('unshareAttachment', attachment)
commit('cardDecreaseAttachmentCount', attachment.cardId)
},

async restoreAttachment({ commit }, attachment) {
const restoredAttachment = await apiClient.restoreAttachment(attachment)
async restoreAttachment({ commit, rootState }, attachment) {
const boardId = rootState.currentBoard.id
const restoredAttachment = await apiClient.restoreAttachment(attachment, boardId)
commit('restoreAttachment', restoredAttachment)
commit('cardIncreaseAttachmentCount', attachment.cardId)
},
Expand Down
Loading