Merge pull request #2730 from nextcloud/feature/add_delete_action_folder
Add delete action for folders
This commit is contained in:
Коммит
1530f48e5a
|
@ -79,6 +79,11 @@ return [
|
|||
'url' => '/api/accounts/{accountId}/folders/{folderId}/stats',
|
||||
'verb' => 'GET'
|
||||
],
|
||||
[
|
||||
'name' => 'folders#delete',
|
||||
'url' => '/api/accounts/{accountId}/folders/{folderId}',
|
||||
'verb' => 'DELETE'
|
||||
],
|
||||
[
|
||||
'name' => 'messages#downloadAttachment',
|
||||
'url' => '/api/accounts/{accountId}/folders/{folderId}/messages/{messageId}/attachment/{attachmentId}',
|
||||
|
|
|
@ -142,4 +142,12 @@ interface IMailManager {
|
|||
* @return Quota|null
|
||||
*/
|
||||
public function getQuota(Account $account): ?Quota;
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param string $folderId
|
||||
*
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public function deleteMailbox(Account $account, string $folderId): void;
|
||||
}
|
||||
|
|
|
@ -234,4 +234,17 @@ class FoldersController extends Controller {
|
|||
|
||||
return new JSONResponse($this->mailManager->createFolder($account, $name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @TrapError
|
||||
* @param int $accountId
|
||||
* @param string $folderId
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public function delete(int $accountId, string $folderId): JSONResponse {
|
||||
$account = $this->accountService->find($this->currentUserId, $accountId);
|
||||
$this->mailManager->deleteMailbox($account, base64_decode($folderId));
|
||||
return new JSONResponse();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -219,4 +219,17 @@ class FolderMapper {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Horde_Imap_Client_Socket $client
|
||||
* @param string $folderId
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public function delete(Horde_Imap_Client_Socket $client, string $folderId): void {
|
||||
try {
|
||||
$client->deleteMailbox($folderId);
|
||||
} catch (Horde_Imap_Client_Exception $e) {
|
||||
throw new ServiceException('Could not delete mailbox: '.$e->getMessage(), 0, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -373,4 +373,21 @@ class MailManager implements IMailManager {
|
|||
1024 * (int)($storage['limit'] ?? 0)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param string $folderId
|
||||
* @throws ServiceException
|
||||
*/
|
||||
public function deleteMailbox(Account $account,
|
||||
string $folderId): void {
|
||||
try {
|
||||
$mailbox = $this->mailboxMapper->find($account, $folderId);
|
||||
} catch (DoesNotExistException $e) {
|
||||
throw new ServiceException("Source mailbox $folderId does not exist", 0, $e);
|
||||
}
|
||||
$client = $this->imapClientFactory->getClient($account);
|
||||
$this->folderMapper->delete($client, $folderId);
|
||||
$this->mailboxMapper->delete($mailbox);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,9 @@
|
|||
@click="clearCache">
|
||||
{{ t('mail', 'Clear locally cached data, in case there are issues with synchronization.') }}
|
||||
</ActionButton>
|
||||
<ActionButton v-if="!account.isUnified && !folder.specialRole" icon="icon-delete" @click="deleteFolder">
|
||||
{{ t('mail', 'Delete folder') }}
|
||||
</ActionButton>
|
||||
</template>
|
||||
</template>
|
||||
<AppNavigationCounter v-if="folder.unread" slot="counter">
|
||||
|
@ -294,6 +297,32 @@ export default {
|
|||
this.clearCache = false
|
||||
}
|
||||
},
|
||||
deleteFolder() {
|
||||
const id = this.folder.id
|
||||
logger.info('delete folder', { folder: this.folder })
|
||||
OC.dialogs.confirmDestructive(
|
||||
t('mail', 'The folder and all messages in it will be deleted.', {
|
||||
folderId: this.folderId,
|
||||
}),
|
||||
t('mail', 'Delete folder'),
|
||||
{
|
||||
type: OC.dialogs.YES_NO_BUTTONS,
|
||||
confirm: t('mail', 'Delete folder {folderId}', { folderId: this.folderId }),
|
||||
confirmClasses: 'error',
|
||||
cancel: t('mail', 'Cancel'),
|
||||
},
|
||||
(result) => {
|
||||
if (result) {
|
||||
return this.$store
|
||||
.dispatch('deleteFolder', { account: this.account, folder: this.folder })
|
||||
.then(() => {
|
||||
logger.info(`folder ${id} deleted`)
|
||||
})
|
||||
.catch((error) => logger.error('could not delete folder', { error }))
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -39,3 +39,12 @@ export function markFolderRead(accountId, folderId) {
|
|||
|
||||
return Axios.post(url).then((resp) => resp.data)
|
||||
}
|
||||
|
||||
export const deleteFolder = async(accountId, folderId) => {
|
||||
const url = generateUrl('/apps/mail/api/accounts/{accountId}/folders/{folderId}', {
|
||||
accountId,
|
||||
folderId,
|
||||
})
|
||||
|
||||
await Axios.delete(url)
|
||||
}
|
||||
|
|
|
@ -50,7 +50,12 @@ import {
|
|||
update as updateAccount,
|
||||
updateSignature,
|
||||
} from '../service/AccountService'
|
||||
import { create as createFolder, fetchAll as fetchAllFolders, markFolderRead } from '../service/FolderService'
|
||||
import {
|
||||
create as createFolder,
|
||||
fetchAll as fetchAllFolders,
|
||||
markFolderRead,
|
||||
deleteFolder,
|
||||
} from '../service/FolderService'
|
||||
import {
|
||||
deleteMessage,
|
||||
fetchEnvelope,
|
||||
|
@ -147,6 +152,10 @@ export default {
|
|||
throw err
|
||||
})
|
||||
},
|
||||
async deleteFolder({ commit }, { account, folder }) {
|
||||
await deleteFolder(account.id, folder.id)
|
||||
commit('removeFolder', { accountId: account.id, folderId: folder.id })
|
||||
},
|
||||
createFolder({ commit }, { account, name }) {
|
||||
return createFolder(account.id, name).then((folder) => {
|
||||
console.debug(`folder ${name} created for account ${account.id}`, { folder })
|
||||
|
|
|
@ -110,6 +110,18 @@ export default {
|
|||
account.folders.push(id)
|
||||
})
|
||||
},
|
||||
removeFolder(state, { accountId, folderId }) {
|
||||
const account = state.accounts[accountId]
|
||||
const id = normalizedFolderId(accountId, folderId)
|
||||
Vue.delete(state.folders, id)
|
||||
account.folders = account.folders.filter((fId) => fId !== id)
|
||||
account.folders.forEach((fId) => {
|
||||
const folder = state.folders[fId]
|
||||
if (folder.folders) {
|
||||
folder.folders = folder.folders.filter((fId) => fId !== id)
|
||||
}
|
||||
})
|
||||
},
|
||||
addEnvelope(state, { accountId, folderId, query, envelope }) {
|
||||
const folder = state.folders[normalizedFolderId(accountId, folderId)]
|
||||
Vue.set(state.envelopes, envelope.uuid, envelope)
|
||||
|
|
|
@ -254,4 +254,88 @@ describe('Vuex store mutations', () => {
|
|||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('removes a folder', () => {
|
||||
const state = {
|
||||
accounts: {
|
||||
13: {
|
||||
accountId: 13,
|
||||
id: 13,
|
||||
folders: ['13-INBOX'],
|
||||
},
|
||||
},
|
||||
folders: {
|
||||
'13-INBOX': {
|
||||
id: 'INBOX',
|
||||
specialUse: ['inbox'],
|
||||
specialRole: 'inbox',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
mutations.removeFolder(state, {
|
||||
accountId: 13,
|
||||
folderId: 'INBOX',
|
||||
})
|
||||
|
||||
expect(state).to.deep.equal({
|
||||
accounts: {
|
||||
13: {
|
||||
accountId: 13,
|
||||
id: 13,
|
||||
folders: [],
|
||||
},
|
||||
},
|
||||
folders: {},
|
||||
})
|
||||
})
|
||||
|
||||
it('removes a subfolder', () => {
|
||||
const state = {
|
||||
accounts: {
|
||||
13: {
|
||||
accountId: 13,
|
||||
id: 13,
|
||||
folders: ['13-INBOX'],
|
||||
},
|
||||
},
|
||||
folders: {
|
||||
'13-INBOX': {
|
||||
id: 'INBOX',
|
||||
specialUse: ['inbox'],
|
||||
specialRole: 'inbox',
|
||||
folders: ['13-INBOX.sub'],
|
||||
},
|
||||
'13-INBOX.sub': {
|
||||
id: 'INBOX.sub',
|
||||
specialUse: ['inbox'],
|
||||
specialRole: 'inbox',
|
||||
folders: [],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
mutations.removeFolder(state, {
|
||||
accountId: 13,
|
||||
folderId: 'INBOX.sub',
|
||||
})
|
||||
|
||||
expect(state).to.deep.equal({
|
||||
accounts: {
|
||||
13: {
|
||||
accountId: 13,
|
||||
id: 13,
|
||||
folders: ['13-INBOX'],
|
||||
},
|
||||
},
|
||||
folders: {
|
||||
'13-INBOX': {
|
||||
id: 'INBOX',
|
||||
specialUse: ['inbox'],
|
||||
specialRole: 'inbox',
|
||||
folders: [],
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
Загрузка…
Ссылка в новой задаче