2121use OCA \Tables \Db \Table ;
2222use OCA \Tables \Db \View ;
2323use OCA \Tables \Db \ViewMapper ;
24+ use OCA \Tables \Errors \BadRequestError ;
2425use OCA \Tables \Errors \InternalError ;
2526use OCA \Tables \Errors \NotFoundError ;
2627use OCA \Tables \Errors \PermissionError ;
@@ -195,11 +196,13 @@ public function findSharedViewsWithMe(?string $userId = null): array {
195196 * @param string|null $emoji
196197 * @param Table $table
197198 * @param string|null $userId
199+ * @param string|null $technicalName
198200 * @return View
199201 * @throws InternalError
200202 * @throws PermissionError
203+ * @throws BadRequestError
201204 */
202- public function create (string $ title , ?string $ emoji , Table $ table , ?string $ userId = null ): View {
205+ public function create (string $ title , ?string $ emoji , Table $ table , ?string $ userId = null , ? string $ technicalName = null ): View {
203206 /** @var string $userId */
204207 $ userId = $ this ->permissionsService ->preCheckUserId ($ userId , false ); // $userId is set
205208
@@ -221,15 +224,26 @@ public function create(string $title, ?string $emoji, Table $table, ?string $use
221224 $ item ->setLastEditBy ($ userId );
222225 $ item ->setCreatedAt ($ time ->format ('Y-m-d H:i:s ' ));
223226 $ item ->setLastEditAt ($ time ->format ('Y-m-d H:i:s ' ));
227+ if ($ technicalName !== null ) {
228+ $ this ->assertTechnicalNameValid ($ technicalName );
229+ $ item ->setTechnicalName ($ technicalName );
230+ }
224231 // ownership is not stored with the record, but it might be necessary upon
225232 // further interaction with the view in the running process, as the instance
226233 // is cached now. The ownership is always inherited from the table.
227234 $ item ->setOwnership ($ table ->getOwnership ());
228235 try {
229236 $ newItem = $ this ->mapper ->insert ($ item );
230237 } catch (\OCP \DB \Exception $ e ) {
231- $ this ->logger ->error ($ e ->getMessage ());
232- throw new InternalError ($ e ->getMessage ());
238+ $ this ->handleViewPersistDbException ($ e , 'create view insert error ' );
239+ }
240+ if ($ newItem ->getTechnicalName () === null || $ newItem ->getTechnicalName () === '' ) {
241+ $ newItem ->setTechnicalName ($ this ->buildDefaultTechnicalName ($ newItem ->getId ()));
242+ try {
243+ $ newItem = $ this ->mapper ->update ($ newItem );
244+ } catch (\OCP \DB \Exception $ e ) {
245+ $ this ->handleViewPersistDbException ($ e , 'create view update error ' );
246+ }
233247 }
234248
235249 $ this ->activityManager ->triggerEvent (
@@ -267,6 +281,10 @@ public function update(int $id, ViewUpdateInput $data, ?string $userId = null, b
267281 $ this ->assertInputColumnsAreValid ($ view , $ userId , $ value );
268282 }
269283
284+ if ($ parameter === ViewUpdatableParameters::TECHNICAL_NAME ) {
285+ $ this ->assertTechnicalNameValid ($ value );
286+ }
287+
270288 if ($ value instanceof JsonSerializable) {
271289 $ insertableValue = json_encode ($ value );
272290 }
@@ -289,8 +307,10 @@ public function update(int $id, ViewUpdateInput $data, ?string $userId = null, b
289307 subject: ActivityManager::SUBJECT_VIEW_UPDATE ,
290308 );
291309 return $ view ;
292- } catch (InvalidArgumentException $ e ) {
310+ } catch (BadRequestError | InvalidArgumentException $ e ) {
293311 throw $ e ;
312+ } catch (\OCP \DB \Exception $ e ) {
313+ $ this ->handleViewPersistDbException ($ e , 'update view error ' );
294314 } catch (Exception $ e ) {
295315 $ this ->logger ->error ($ e ->getMessage (), ['exception ' => $ e ]);
296316 throw new InternalError ($ e ->getMessage ());
@@ -640,6 +660,11 @@ public function importView(int $tableId, array $view, string $userId): void {
640660 $ item ->setTableId ($ tableId );
641661 $ item ->setTitle ($ view ['title ' ]);
642662 $ item ->setEmoji ($ view ['emoji ' ]);
663+ $ technicalName = $ view ['technicalName ' ] ?? null ;
664+ if ($ technicalName !== null ) {
665+ $ this ->assertTechnicalNameValid ($ technicalName );
666+ $ item ->setTechnicalName ($ technicalName );
667+ }
643668 $ item ->setCreatedBy ($ userId );
644669 $ item ->setCreatedAt ($ view ['createdAt ' ]);
645670 $ item ->setLastEditBy ($ userId );
@@ -650,9 +675,44 @@ public function importView(int $tableId, array $view, string $userId): void {
650675 $ item ->setFilter (json_encode ($ view ['filter ' ]));
651676 try {
652677 $ this ->mapper ->insert ($ item );
678+ if ($ item ->getTechnicalName () === null || $ item ->getTechnicalName () === '' ) {
679+ $ item ->setTechnicalName ($ this ->buildDefaultTechnicalName ($ item ->getId ()));
680+ $ this ->mapper ->update ($ item );
681+ }
682+ } catch (\OCP \DB \Exception $ e ) {
683+ $ this ->handleViewPersistDbException ($ e , 'importView insert error ' );
653684 } catch (\Exception $ e ) {
654685 $ this ->logger ->error ('userMigrationImport insert error: ' . $ e ->getMessage ());
655686 throw new InternalError ('userMigrationImport insert error: ' . $ e ->getMessage ());
656687 }
657688 }
689+
690+ private function buildDefaultTechnicalName (int $ viewId ): string {
691+ return 'view_ ' . $ viewId ;
692+ }
693+
694+ /**
695+ * @throws BadRequestError
696+ */
697+ private function assertTechnicalNameValid (string $ technicalName ): void {
698+ if (strlen ($ technicalName ) > 200 ) {
699+ throw new BadRequestError ('Technical name must not exceed 200 characters. ' );
700+ }
701+ if (!preg_match ('/^[a-z][a-z0-9_]*$/ ' , $ technicalName )) {
702+ throw new BadRequestError ('Technical name must start with a lowercase letter and contain only lowercase letters, numbers, and underscores. ' );
703+ }
704+ }
705+
706+ /**
707+ * @throws BadRequestError
708+ * @throws InternalError
709+ */
710+ private function handleViewPersistDbException (\OCP \DB \Exception $ e , string $ context ): never {
711+ if ($ e ->getReason () === \OCP \DB \Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION ) {
712+ throw new BadRequestError ('Technical name must be unique in the table. ' );
713+ }
714+
715+ $ this ->logger ->error ($ e ->getMessage (), ['exception ' => $ e ]);
716+ throw new InternalError ($ context . ': ' . $ e ->getMessage ());
717+ }
658718}
0 commit comments