Skip to content

Commit

Permalink
Merge pull request #1170 from nextcloud/feat/template-schema-export
Browse files Browse the repository at this point in the history
add scheme import and export
  • Loading branch information
grnd-alt committed Jul 25, 2024
2 parents 1fb28ae + 9255651 commit 8944979
Show file tree
Hide file tree
Showing 12 changed files with 1,034 additions and 2 deletions.
3 changes: 3 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
['name' => 'api1#createTable', 'url' => '/api/1/tables', 'verb' => 'POST'],
['name' => 'api1#updateTable', 'url' => '/api/1/tables/{tableId}', 'verb' => 'PUT'],
['name' => 'api1#getTable', 'url' => '/api/1/tables/{tableId}', 'verb' => 'GET'],
['name' => 'api1#showScheme', 'url' => '/api/1/tables/{tableId}/scheme', 'verb' => 'GET'],
['name' => 'api1#deleteTable', 'url' => '/api/1/tables/{tableId}', 'verb' => 'DELETE'],
// -> views
['name' => 'api1#indexViews', 'url' => '/api/1/tables/{tableId}/views', 'verb' => 'GET'],
Expand Down Expand Up @@ -121,6 +122,8 @@
// -> tables
['name' => 'ApiTables#index', 'url' => '/api/2/tables', 'verb' => 'GET'],
['name' => 'ApiTables#show', 'url' => '/api/2/tables/{id}', 'verb' => 'GET'],
['name' => 'ApiTables#showScheme', 'url' => '/api/2/tables/scheme/{id}', 'verb' => 'GET'],
['name' => 'ApiTables#createFromScheme', 'url' => '/api/2/tables/scheme', 'verb' => 'POST'],
['name' => 'ApiTables#create', 'url' => '/api/2/tables', 'verb' => 'POST'],
['name' => 'ApiTables#update', 'url' => '/api/2/tables/{id}', 'verb' => 'PUT'],
['name' => 'ApiTables#destroy', 'url' => '/api/2/tables/{id}', 'verb' => 'DELETE'],
Expand Down
33 changes: 33 additions & 0 deletions lib/Controller/Api1Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,39 @@ public function createTable(string $title, ?string $emoji, string $template = 'c
}
}

/**
* returns table scheme
*
* @NoAdminRequired
* @CORS
* @NoCSRFRequired
*
* @param int $tableId Table ID
* @return DataResponse<Http::STATUS_OK, TablesTable, array{'Content-Disposition'?:string,'Content-Type'?:string}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}>
*
* 200: Table returned
* 403: No permissions
* 404: Not found
*/
public function showScheme(int $tableId): DataResponse {
try {
$scheme = $this->tableService->getScheme($tableId);
return new DataResponse($scheme->jsonSerialize(), http::STATUS_OK, ['Content-Disposition' => 'attachment; filename="'.$scheme->getTitle() . '.json"', 'Content-Type' => 'application/octet-stream']);
} catch (PermissionError $e) {
$this->logger->warning('A permission error occurred: ' . $e->getMessage());
$message = ['message' => $e->getMessage()];
return new DataResponse($message, Http::STATUS_FORBIDDEN);
} catch (NotFoundError $e) {
$this->logger->warning('A not found error occurred: ' . $e->getMessage());
$message = ['message' => $e->getMessage()];
return new DataResponse($message, Http::STATUS_NOT_FOUND);
} catch (InternalError|Exception $e) {
$this->logger->warning('An internal error or exception occurred: '.$e->getMessage());
$message = ['message' => $e->getMessage()];
return new DataResponse($message, Http::STATUS_INTERNAL_SERVER_ERROR);
}
}

/**
* Get a table object
*
Expand Down
109 changes: 109 additions & 0 deletions lib/Controller/ApiTablesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,45 @@
use OCA\Tables\Errors\NotFoundError;
use OCA\Tables\Errors\PermissionError;
use OCA\Tables\ResponseDefinitions;
use OCA\Tables\Service\ColumnService;
use OCA\Tables\Service\TableService;
use OCA\Tables\Service\ViewService;
use OCP\App\IAppManager;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\IDBConnection;
use OCP\IL10N;
use OCP\IRequest;
use Psr\Log\LoggerInterface;

/**
* @psalm-import-type TablesTable from ResponseDefinitions
* @psalm-import-type TablesView from ResponseDefinitions
* @psalm-import-type TablesColumn from ResponseDefinitions
*/
class ApiTablesController extends AOCSController {
private TableService $service;
private ColumnService $columnService;
private ViewService $viewService;
private IAppManager $appManager;
private IDBConnection $db;

public function __construct(
IRequest $request,
LoggerInterface $logger,
TableService $service,
ColumnService $columnService,
ViewService $viewService,
IL10N $n,
IAppManager $appManager,
IDBConnection $db,
string $userId) {
parent::__construct($request, $logger, $n, $userId);
$this->service = $service;
$this->columnService = $columnService;
$this->appManager = $appManager;
$this->viewService = $viewService;
$this->db = $db;
}

/**
Expand Down Expand Up @@ -71,6 +89,97 @@ public function show(int $id): DataResponse {
}
}

/**
* [api v2] Get a table Scheme
*
* @NoAdminRequired
*
* @param int $id Table ID
* @return DataResponse<Http::STATUS_OK, TablesTable, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NOT_FOUND, array{message: string}, array{}>
*
* 200: Scheme returned
* 403: No permissions
* 404: Not found
*/
public function showScheme(int $id): DataResponse {
try {
return new DataResponse($this->service->getScheme($id)->jsonSerialize());
} catch (PermissionError $e) {
return $this->handlePermissionError($e);
} catch (InternalError $e) {
return $this->handleError($e);
} catch (NotFoundError $e) {
return $this->handleNotFoundError($e);
}
}

/**
* @NoAdminRequired
*
* creates table from scheme
*
* @param string $title title of new table
* @param string $emoji emoji
* @param string $description description
* @param array<TablesColumn > $columns columns
* @param array<TablesView> $views views
* @return DataResponse<Http::STATUS_OK, TablesTable, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR, array{message: string}, array{}>
*
* 200: Tables returned
*/
public function createFromScheme(string $title, string $emoji, string $description, array $columns, array $views): DataResponse {
try {
$this->db->beginTransaction();
$table = $this->service->create($title, 'custom', $emoji, $description);
foreach ($columns as $column) {
$this->columnService->create(
$this->userId,
$table->getId(),
null,
$column['type'],
$column['subtype'],
$column['title'],
$column['mandatory'],
$column['description'],

$column['textDefault'],
$column['textAllowedPattern'],
$column['textMaxLength'],

$column['numberPrefix'],
$column['numberSuffix'],
$column['numberDefault'],
$column['numberMin'],
$column['numberMax'],
$column['numberDecimals'],

$column['selectionOptions'] == [] ? '' : $column['selectionOptions'],
$column['selectionDefault'],

$column['datetimeDefault'],
[],
);
};
foreach ($views as $view) {
$this->viewService->create(
$view['title'],
$view['emoji'],
$table,
$this->userId,
);
}
$this->db->commit();
return new DataResponse($table->jsonSerialize());
} catch(InternalError | Exception $e) {
try {
$this->db->rollBack();
} catch (\OCP\DB\Exception $e) {
return $this->handleError($e);
}
return $this->handleError($e);
}
}

/**
* [api v2] Create a new table and return it
*
Expand Down
57 changes: 57 additions & 0 deletions lib/Controller/TableScheme.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace OCA\Tables\Model;

use JsonSerializable;
use OCA\Tables\Db\Column;
use OCA\Tables\Db\View;

class TableScheme implements JsonSerializable {

protected ?string $title = null;
protected ?string $emoji = null;

/** @var Column[]|null */
protected ?array $columns = null;

/** @var View[]|null */
protected ?array $views = null;
protected ?string $description = null;
protected ?string $tablesVersion = null;

public function __construct(string $title, string $emoji, array $columns, array $view, string $description, string $tablesVersion) {
$this->tablesVersion = $tablesVersion;
$this->title = $title;
$this->emoji = $emoji;
$this->columns = $columns;
$this->description = $description;
$this->views = $view;
}

public function getTitle():string {
return $this->title | '';
}

public function jsonSerialize(): array {
return [
'title' => $this->title ?: '',
'emoji' => $this->emoji,
'columns' => $this->columns,
'views' => $this->views,
'description' => $this->description ?:'',
'tablesVersion' => $this->tablesVersion,
];
}

public function getEmoji(): ?string {
return $this->emoji;
}

public function getColumns(): ?array {
return $this->columns;
}

public function getDescription(): ?string {
return $this->description;
}
}
2 changes: 2 additions & 0 deletions lib/Db/Table.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
* @psalm-import-type TablesView from ResponseDefinitions
*
* @method getTitle(): string
* @method getId(): int
* @method setTitle(string $title)
* @method getEmoji(): string
* @method setEmoji(string $emoji)
* @method getArchived(): bool
* @method setArchived(bool $archived)
* @method getDescription(): string
* @method setDescription(string $description)
* @method getOwnership(): string
* @method setOwnership(string $ownership)
Expand Down
18 changes: 17 additions & 1 deletion lib/Service/TableService.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
use OCA\Tables\Event\TableDeletedEvent;
use OCA\Tables\Event\TableOwnershipTransferredEvent;
use OCA\Tables\Helper\UserHelper;
use OCA\Tables\Model\TableScheme;
use OCA\Tables\ResponseDefinitions;
use OCP\App\IAppManager;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\DB\Exception as OcpDbException;
Expand Down Expand Up @@ -42,6 +44,7 @@ class TableService extends SuperService {

protected FavoritesService $favoritesService;

protected IAppManager $appManager;

protected IL10N $l;
private ContextService $contextService;
Expand All @@ -62,9 +65,11 @@ public function __construct(
FavoritesService $favoritesService,
IEventDispatcher $eventDispatcher,
ContextService $contextService,
IAppManager $appManager,
IL10N $l,
) {
parent::__construct($logger, $userId, $permissionsService);
$this->appManager = $appManager;
$this->mapper = $mapper;
$this->tableTemplateService = $tableTemplateService;
$this->columnService = $columnService;
Expand Down Expand Up @@ -533,11 +538,22 @@ public function search(string $term, int $limit = 100, int $offset = 0, ?string
$this->enhanceTable($table, $userId);
}
return $tables;
} catch (InternalError | PermissionError |OcpDbException $e) {
} catch (InternalError | PermissionError | OcpDbException $e) {
return [];
}
}

/**
* @throws PermissionError
* @throws NotFoundError
* @throws InternalError
*/
public function getScheme(int $id): TableScheme {
$columns = $this->columnService->findAllByTable($id);
$table = $this->find($id);
return new TableScheme($table->getTitle(), $table->getEmoji(), $columns, $table->getViews(), $table->getDescription(), $this->appManager->getAppVersion("tables"));
}

// PRIVATE FUNCTIONS ---------------------------------------------------------------

/**
Expand Down
Loading

0 comments on commit 8944979

Please sign in to comment.