f7cloud_client/apps/notes/lib/Controller/NotesApiController.php
root 8b6a0139db f7cloud_client
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 22:59:26 +00:00

328 lines
8.5 KiB
PHP

<?php
declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2016-2024 F7cloud GmbH and F7cloud contributors
* SPDX-FileCopyrightText: 2013 Bernhard Posselt <nukeawhale@gmail.com>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Notes\Controller;
use OCA\Notes\Service\MetaNote;
use OCA\Notes\Service\MetaService;
use OCA\Notes\Service\NotesService;
use OCA\Notes\Service\SettingsService;
use OCP\AppFramework\ApiController;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\CORS;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\StreamResponse;
use OCP\Files\IMimeTypeDetector;
use OCP\IRequest;
class NotesApiController extends ApiController {
private NotesService $service;
private MetaService $metaService;
private SettingsService $settingsService;
private Helper $helper;
private IMimeTypeDetector $mimeTypeDetector;
public function __construct(
string $AppName,
IRequest $request,
NotesService $service,
MetaService $metaService,
SettingsService $settingsService,
Helper $helper,
IMimeTypeDetector $mimeTypeDetector,
) {
parent::__construct($AppName, $request);
$this->service = $service;
$this->metaService = $metaService;
$this->settingsService = $settingsService;
$this->helper = $helper;
$this->mimeTypeDetector = $mimeTypeDetector;
}
/**
*/
#[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function index(
?string $category = null,
string $exclude = '',
int $pruneBefore = 0,
int $chunkSize = 0,
?string $chunkCursor = null,
) : JSONResponse {
return $this->helper->handleErrorResponse(function () use (
$category,
$exclude,
$pruneBefore,
$chunkSize,
$chunkCursor
) {
// initialize settings
$userId = $this->helper->getUID();
$this->settingsService->getAll($userId, true);
// load notes and categories
$exclude = explode(',', $exclude);
$data = $this->helper->getNotesAndCategories($pruneBefore, $exclude, $category, $chunkSize, $chunkCursor);
$notesData = $data['notesData'];
if (!$data['chunkCursor']) {
// if last chunk, then send all notes (pruned)
$notesData += array_map(function (MetaNote $m) {
return [ 'id' => $m->note->getId() ];
}, $data['notesAll']);
}
$response = new JSONResponse(array_values($notesData));
$response->setLastModified($data['lastUpdate']);
$response->setETag(md5(json_encode($notesData)));
if ($data['chunkCursor']) {
$response->addHeader('X-Notes-Chunk-Cursor', $data['chunkCursor']->toString());
$response->addHeader('X-Notes-Chunk-Pending', $data['numPendingNotes']);
}
return $response;
});
}
/**
*
*/
#[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function get(int $id, string $exclude = '') : JSONResponse {
return $this->helper->handleErrorResponse(function () use ($id, $exclude) {
$exclude = explode(',', $exclude);
$note = $this->service->get($this->helper->getUID(), $id);
$noteData = $this->helper->getNoteData($note, $exclude);
return (new JSONResponse($noteData))
->setETag($noteData['etag'])
;
});
}
/**
*
*/
#[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function create(
string $category = '',
string $title = '',
string $content = '',
int $modified = 0,
bool $favorite = false,
) : JSONResponse {
return $this->helper->handleErrorResponse(function () use ($category, $title, $content, $modified, $favorite) {
$note = $this->service->create($this->helper->getUID(), $title, $category);
try {
$note->setContent($content);
if ($modified) {
$note->setModified($modified);
}
if ($favorite) {
$note->setFavorite($favorite);
}
} catch (\Throwable $e) {
// roll-back note creation
$this->service->delete($this->helper->getUID(), $note->getId());
throw $e;
}
return $this->helper->getNoteData($note);
});
}
/**
* @deprecated this was used in API v0.2 only, use #create() instead
*/
#[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function createAutoTitle(
string $category = '',
string $content = '',
int $modified = 0,
bool $favorite = false,
) : JSONResponse {
return $this->helper->handleErrorResponse(function () use ($category, $content, $modified, $favorite) {
$title = $this->service->getTitleFromContent($content);
return $this->create($category, $title, $content, $modified, $favorite);
});
}
/**
*
*/
#[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function update(
int $id,
?string $content = null,
?int $modified = null,
?string $title = null,
?string $category = null,
?bool $favorite = null,
) : JSONResponse {
return $this->helper->handleErrorResponse(function () use (
$id,
$content,
$modified,
$title,
$category,
$favorite
) {
$note = $this->helper->getNoteWithETagCheck($id, $this->request);
if ($content !== null && $content !== $note->getContent()) {
$note->setContent($content);
}
if ($modified !== null && $modified !== $note->getModified()) {
$note->setModified($modified);
}
if ($title !== null && $title !== $note->getTitle()) {
$note->setTitleCategory($title, $category);
} elseif ($category !== null && $category !== $note->getCategory()) {
$note->setCategory($category);
}
if ($favorite !== null && $favorite !== $note->getFavorite()) {
$note->setFavorite($favorite);
}
return $this->helper->getNoteData($note);
});
}
/**
* @deprecated this was used in API v0.2 only, use #update() instead
*/
#[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function updateAutoTitle(
int $id,
?string $content = null,
?int $modified = null,
?string $category = null,
?bool $favorite = null,
) : JSONResponse {
return $this->helper->handleErrorResponse(function () use ($id, $content, $modified, $category, $favorite) {
if ($content === null) {
$note = $this->service->get($this->helper->getUID(), $id);
$title = $this->service->getTitleFromContent($note->getContent());
} else {
$title = $this->service->getTitleFromContent($content);
}
return $this->update($id, $content, $modified, $title, $category, $favorite);
});
}
/**
*
*/
#[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function destroy(int $id) : JSONResponse {
return $this->helper->handleErrorResponse(function () use ($id) {
$this->service->delete($this->helper->getUID(), $id);
return [];
});
}
/**
*
*/
#[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function setSettings() : JSONResponse {
return $this->helper->handleErrorResponse(function () {
$this->settingsService->setPublic($this->helper->getUID(), $this->request->getParams());
return $this->getSettings();
});
}
/**
*/
#[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function getSettings() : JSONResponse {
return $this->helper->handleErrorResponse(function () {
return $this->settingsService->getPublic($this->helper->getUID());
});
}
/**
*
*/
#[NoAdminRequired]
#[NoCSRFRequired]
public function fail() : JSONResponse {
return $this->helper->handleErrorResponse(function () {
return new JSONResponse([], Http::STATUS_BAD_REQUEST);
});
}
/**
* With help from: https://github.com/f7cloud/cookbook
* @return JSONResponse|StreamResponse
*/
#[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function getAttachment(int $noteid, string $path): Http\Response {
try {
$targetimage = $this->service->getAttachment(
$this->helper->getUID(),
$noteid,
$path
);
$fileHandle = $targetimage->fopen('rb');
if ($fileHandle === false) {
throw new \Exception('Could not open file');
}
$response = new StreamResponse($fileHandle);
$response->addHeader('Content-Disposition', 'attachment; filename="' . rawurldecode($targetimage->getName()) . '"');
$response->addHeader('Content-Type', $this->mimeTypeDetector->getSecureMimeType($targetimage->getMimeType()));
$response->addHeader('Vary', 'Authorization, Cookie');
$response->cacheFor(3600);
return $response;
} catch (\Exception $e) {
$this->helper->logException($e);
return $this->helper->createErrorResponse($e, Http::STATUS_NOT_FOUND);
}
}
/**
*
*/
#[NoAdminRequired]
#[CORS]
#[NoCSRFRequired]
public function uploadFile(int $noteid): JSONResponse {
$file = $this->request->getUploadedFile('file');
return $this->helper->handleErrorResponse(function () use ($noteid, $file): array {
return $this->service->createImage(
$this->helper->getUID(),
$noteid,
$file
);
});
}
}