1919use OCA \Tables \Db \Table ;
2020use OCA \Tables \Db \View ;
2121use OCA \Tables \Db \ViewMapper ;
22+ use OCA \Tables \Errors \BadRequestError ;
2223use OCA \Tables \Errors \InternalError ;
2324use OCA \Tables \Errors \NotFoundError ;
2425use OCA \Tables \Errors \PermissionError ;
@@ -189,11 +190,13 @@ public function findSharedViewsWithMe(?string $userId = null): array {
189190 * @param string|null $emoji
190191 * @param Table $table
191192 * @param string|null $userId
193+ * @param string|null $technicalName
192194 * @return View
193195 * @throws InternalError
194196 * @throws PermissionError
197+ * @throws BadRequestError
195198 */
196- public function create (string $ title , ?string $ emoji , Table $ table , ?string $ userId = null ): View {
199+ public function create (string $ title , ?string $ emoji , Table $ table , ?string $ userId = null , ? string $ technicalName = null ): View {
197200 /** @var string $userId */
198201 $ userId = $ this ->permissionsService ->preCheckUserId ($ userId , false ); // $userId is set
199202
@@ -214,6 +217,11 @@ public function create(string $title, ?string $emoji, Table $table, ?string $use
214217 $ item ->setLastEditBy ($ userId );
215218 $ item ->setCreatedAt ($ time ->format ('Y-m-d H:i:s ' ));
216219 $ item ->setLastEditAt ($ time ->format ('Y-m-d H:i:s ' ));
220+ if ($ technicalName !== null ) {
221+ $ this ->assertTechnicalNameValid ($ technicalName );
222+ $ this ->assertTechnicalNameUnique ($ table ->getId (), $ technicalName );
223+ $ item ->setTechnicalName ($ technicalName );
224+ }
217225 // ownership is not stored with the record, but it might be necessary upon
218226 // further interaction with the view in the running process, as the instance
219227 // is cached now. The ownership is always inherited from the table.
@@ -224,6 +232,15 @@ public function create(string $title, ?string $emoji, Table $table, ?string $use
224232 $ this ->logger ->error ($ e ->getMessage ());
225233 throw new InternalError ($ e ->getMessage ());
226234 }
235+ if ($ newItem ->getTechnicalName () === null || $ newItem ->getTechnicalName () === '' ) {
236+ $ newItem ->setTechnicalName ($ this ->buildDefaultTechnicalName ($ newItem ->getId ()));
237+ try {
238+ $ newItem = $ this ->mapper ->update ($ newItem );
239+ } catch (\OCP \DB \Exception $ e ) {
240+ $ this ->logger ->error ($ e ->getMessage ());
241+ throw new InternalError ($ e ->getMessage (), previous: $ e );
242+ }
243+ }
227244
228245 return $ newItem ;
229246 }
@@ -251,6 +268,11 @@ public function update(int $id, ViewUpdateInput $data, ?string $userId = null, b
251268 $ this ->assertInputColumnsAreValid ($ view , $ userId , $ value );
252269 }
253270
271+ if ($ parameter === ViewUpdatableParameters::TECHNICAL_NAME ) {
272+ $ this ->assertTechnicalNameValid ($ value );
273+ $ this ->assertTechnicalNameUnique ($ view ->getTableId (), $ value , $ view ->getId ());
274+ }
275+
254276 if ($ value instanceof JsonSerializable) {
255277 $ insertableValue = json_encode ($ value );
256278 }
@@ -267,7 +289,7 @@ public function update(int $id, ViewUpdateInput $data, ?string $userId = null, b
267289 $ this ->enhanceView ($ view , $ userId );
268290 }
269291 return $ view ;
270- } catch (InvalidArgumentException $ e ) {
292+ } catch (BadRequestError | InvalidArgumentException $ e ) {
271293 throw $ e ;
272294 } catch (Exception $ e ) {
273295 $ this ->logger ->error ($ e ->getMessage (), ['exception ' => $ e ]);
@@ -610,6 +632,7 @@ public function importView(int $tableId, array $view, string $userId): void {
610632 $ item ->setTableId ($ tableId );
611633 $ item ->setTitle ($ view ['title ' ]);
612634 $ item ->setEmoji ($ view ['emoji ' ]);
635+ $ item ->setTechnicalName ($ view ['technicalName ' ] ?? null );
613636 $ item ->setCreatedBy ($ userId );
614637 $ item ->setCreatedAt ($ view ['createdAt ' ]);
615638 $ item ->setLastEditBy ($ userId );
@@ -620,9 +643,51 @@ public function importView(int $tableId, array $view, string $userId): void {
620643 $ item ->setFilter (json_encode ($ view ['filter ' ]));
621644 try {
622645 $ this ->mapper ->insert ($ item );
646+ if ($ item ->getTechnicalName () === null || $ item ->getTechnicalName () === '' ) {
647+ $ item ->setTechnicalName ($ this ->buildDefaultTechnicalName ($ item ->getId ()));
648+ $ this ->mapper ->update ($ item );
649+ }
650+ } catch (BadRequestError $ e ) {
651+ throw $ e ;
623652 } catch (\Exception $ e ) {
624653 $ this ->logger ->error ('userMigrationImport insert error: ' . $ e ->getMessage ());
625654 throw new InternalError ('userMigrationImport insert error: ' . $ e ->getMessage ());
626655 }
627656 }
657+
658+ private function buildDefaultTechnicalName (int $ viewId ): string {
659+ return 'view_ ' . $ viewId ;
660+ }
661+
662+ /**
663+ * @throws BadRequestError
664+ */
665+ private function assertTechnicalNameValid (string $ technicalName ): void {
666+ if (!preg_match ('/^[a-z][a-z0-9_]*$/ ' , $ technicalName )) {
667+ throw new BadRequestError ('Technical name must start with a lowercase letter and contain only lowercase letters, numbers, and underscores. ' );
668+ }
669+ }
670+
671+ /**
672+ * @throws BadRequestError
673+ * @throws InternalError
674+ */
675+ private function assertTechnicalNameUnique (int $ tableId , string $ technicalName , ?int $ excludeCurrentViewId = null ): void {
676+ try {
677+ $ views = $ this ->mapper ->findAll ($ tableId );
678+ } catch (\OCP \DB \Exception $ e ) {
679+ $ this ->logger ->error ($ e ->getMessage (), ['exception ' => $ e ]);
680+ throw new InternalError (get_class ($ this ) . ' - ' . __FUNCTION__ . ': ' . $ e ->getMessage (), previous: $ e );
681+ }
682+
683+ foreach ($ views as $ view ) {
684+ if ($ excludeCurrentViewId !== null && $ view ->getId () === $ excludeCurrentViewId ) {
685+ continue ;
686+ }
687+
688+ if ($ view ->getTechnicalName () === $ technicalName ) {
689+ throw new BadRequestError ('Technical name must be unique in the table. ' );
690+ }
691+ }
692+ }
628693}
0 commit comments