99namespace OCA \Tables \Controller ;
1010
1111use OCA \Tables \AppInfo \Application ;
12+ use OCA \Tables \Db \Row2Mapper ;
1213use OCA \Tables \Errors \BadRequestError ;
1314use OCA \Tables \Errors \InternalError ;
1415use OCA \Tables \Errors \NotFoundError ;
1516use OCA \Tables \Errors \PermissionError ;
1617use OCA \Tables \Helper \ConversionHelper ;
1718use OCA \Tables \Middleware \Attribute \AssertShareAccessIsAccessible ;
19+ use OCA \Tables \Model \RowDataInput ;
1820use OCA \Tables \ResponseDefinitions ;
1921use OCA \Tables \Service \RowService ;
2022use OCA \Tables \Service \ShareService ;
@@ -37,11 +39,13 @@ class PublicRowOCSController extends AOCSController {
3739 public function __construct (
3840 protected ShareService $ shareService ,
3941 protected RowService $ rowService ,
42+ protected Row2Mapper $ row2Mapper ,
4043 IRequest $ request ,
4144 LoggerInterface $ logger ,
4245 IL10N $ l ,
4346 ) {
4447 parent ::__construct ($ request , $ logger , $ l , '' );
48+ $ this ->rowService ->setPublicContext ();
4549 }
4650
4751 /**
@@ -68,6 +72,10 @@ public function getRows(string $token, ?int $limit, ?int $offset): DataResponse
6872 $ shareToken = new ShareToken ($ token );
6973 $ share = $ this ->shareService ->findByToken ($ shareToken );
7074
75+ if (!$ share ->getPermissionRead ()) {
76+ return $ this ->handlePermissionError (new PermissionError ('No read permission on this share ' ));
77+ }
78+
7179 $ limit = $ limit !== null ? max (0 , min (500 , $ limit )) : null ;
7280 $ offset = $ offset !== null ? max (0 , $ offset ) : null ;
7381
@@ -90,4 +98,165 @@ public function getRows(string $token, ?int $limit, ?int $offset): DataResponse
9098 return $ this ->handleBadRequestError ($ e );
9199 }
92100 }
101+
102+ /**
103+ * [api v2] Create a row in a link share
104+ *
105+ * @param string $token The share token
106+ * @param string|array<string, mixed> $data An array containing the column identifiers and their values
107+ * @return DataResponse<Http::STATUS_OK, TablesPublicRow, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_BAD_REQUEST|Http::STATUS_NOT_FOUND|Http::STATUS_INTERNAL_SERVER_ERROR, array{message: string}, array{}>
108+ *
109+ * 200: Row created
110+ * 400: Invalid request parameters
111+ * 403: No permissions
112+ * 404: Not found
113+ * 500: Internal error
114+ */
115+ #[PublicPage]
116+ #[AssertShareAccessIsAccessible]
117+ #[ApiRoute(verb: 'POST ' , url: '/api/2/public/{token}/rows ' , requirements: ['token ' => '[a-zA-Z0-9]{16} ' ])]
118+ #[OpenAPI]
119+ #[AnonRateLimit(limit: 20 , period: 30 )]
120+ public function createRow (string $ token , mixed $ data ): DataResponse {
121+ try {
122+ $ shareToken = new ShareToken ($ token );
123+ $ share = $ this ->shareService ->findByToken ($ shareToken );
124+ $ this ->row2Mapper ->setUserId ('public- ' . $ token );
125+
126+ if (!$ share ->getPermissionCreate ()) {
127+ return $ this ->handlePermissionError (new PermissionError ('No create permission on this share ' ));
128+ }
129+
130+ if (is_string ($ data )) {
131+ $ data = json_decode ($ data , true );
132+ }
133+ if (!is_array ($ data )) {
134+ return $ this ->handleBadRequestError (new BadRequestError ('Invalid data input ' ));
135+ }
136+
137+ $ newRowData = new RowDataInput ();
138+ foreach ($ data as $ key => $ value ) {
139+ $ newRowData ->add ((int )$ key , $ value );
140+ }
141+
142+ $ tableId = $ share ->getNodeType () === 'table ' ? $ share ->getNodeId () : null ;
143+ $ viewId = $ share ->getNodeType () === 'view ' ? $ share ->getNodeId () : null ;
144+
145+ if ($ viewId === null && $ tableId === null ) {
146+ throw new InternalError ('Cannot create row without table or view provided ' );
147+ }
148+
149+ $ row = $ this ->rowService ->create ($ tableId , $ viewId , $ newRowData );
150+ return new DataResponse ($ this ->rowService ->formatRowsForPublicShare ([$ row ])[0 ]);
151+ } catch (PermissionError $ e ) {
152+ return $ this ->handlePermissionError ($ e );
153+ } catch (NotFoundError $ e ) {
154+ return $ this ->handleNotFoundError ($ e );
155+ } catch (BadRequestError $ e ) {
156+ return $ this ->handleBadRequestError ($ e );
157+ } catch (InternalError |\Exception $ e ) {
158+ return $ this ->handleError ($ e );
159+ }
160+ }
161+
162+ /**
163+ * [api v2] Update a row in a link share
164+ *
165+ * @param string $token The share token
166+ * @param int $rowId The row identifier
167+ * @param string|array<string, mixed> $data An array containing the column identifiers and their values
168+ * @return DataResponse<Http::STATUS_OK, TablesPublicRow, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_BAD_REQUEST|Http::STATUS_NOT_FOUND|Http::STATUS_INTERNAL_SERVER_ERROR, array{message: string}, array{}>
169+ *
170+ * 200: Row updated
171+ * 400: Invalid request parameters
172+ * 403: No permissions
173+ * 404: Not found
174+ * 500: Internal error
175+ */
176+ #[PublicPage]
177+ #[AssertShareAccessIsAccessible]
178+ #[ApiRoute(verb: 'PUT ' , url: '/api/2/public/{token}/rows/{rowId} ' , requirements: ['token ' => '[a-zA-Z0-9]{16} ' , 'rowId ' => '\d+ ' ])]
179+ #[OpenAPI]
180+ #[AnonRateLimit(limit: 20 , period: 30 )]
181+ public function updateRow (string $ token , int $ rowId , mixed $ data ): DataResponse {
182+ try {
183+ $ shareToken = new ShareToken ($ token );
184+ $ share = $ this ->shareService ->findByToken ($ shareToken );
185+ $ this ->row2Mapper ->setUserId ('public- ' . $ token );
186+
187+ if (!$ share ->getPermissionUpdate ()) {
188+ return $ this ->handlePermissionError (new PermissionError ('No update permission on this share ' ));
189+ }
190+
191+ if (is_string ($ data )) {
192+ $ data = json_decode ($ data , true );
193+ }
194+ if (!is_array ($ data )) {
195+ return $ this ->handleBadRequestError (new BadRequestError ('Invalid data input ' ));
196+ }
197+
198+ $ viewId = $ share ->getNodeType () === 'view ' ? $ share ->getNodeId () : null ;
199+ $ tableId = $ share ->getNodeType () === 'table ' ? $ share ->getNodeId () : null ;
200+
201+ if ($ viewId === null && $ tableId === null ) {
202+ throw new InternalError ('Cannot update row without table or view provided ' );
203+ }
204+
205+ $ row = $ this ->rowService ->updateSet ($ rowId , $ viewId , $ data , '' , $ tableId );
206+ return new DataResponse ($ this ->rowService ->formatRowsForPublicShare ([$ row ])[0 ]);
207+ } catch (PermissionError $ e ) {
208+ return $ this ->handlePermissionError ($ e );
209+ } catch (NotFoundError $ e ) {
210+ return $ this ->handleNotFoundError ($ e );
211+ } catch (BadRequestError $ e ) {
212+ return $ this ->handleBadRequestError ($ e );
213+ } catch (InternalError |\Exception $ e ) {
214+ return $ this ->handleError ($ e );
215+ }
216+ }
217+
218+ /**
219+ * [api v2] Delete a row in a link share
220+ *
221+ * @param string $token The share token
222+ * @param int $rowId The row identifier
223+ * @return DataResponse<Http::STATUS_OK, TablesPublicRow, array{}>|DataResponse<Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND|Http::STATUS_INTERNAL_SERVER_ERROR, array{message: string}, array{}>
224+ *
225+ * 200: Row deleted
226+ * 403: No permissions
227+ * 404: Not found
228+ * 500: Internal error
229+ */
230+ #[PublicPage]
231+ #[AssertShareAccessIsAccessible]
232+ #[ApiRoute(verb: 'DELETE ' , url: '/api/2/public/{token}/rows/{rowId} ' , requirements: ['token ' => '[a-zA-Z0-9]{16} ' , 'rowId ' => '\d+ ' ])]
233+ #[OpenAPI]
234+ #[AnonRateLimit(limit: 20 , period: 30 )]
235+ public function deleteRow (string $ token , int $ rowId ): DataResponse {
236+ try {
237+ $ shareToken = new ShareToken ($ token );
238+ $ share = $ this ->shareService ->findByToken ($ shareToken );
239+ $ this ->row2Mapper ->setUserId ('public- ' . $ token );
240+
241+ if (!$ share ->getPermissionDelete ()) {
242+ return $ this ->handlePermissionError (new PermissionError ('No delete permission on this share ' ));
243+ }
244+
245+ $ viewId = $ share ->getNodeType () === 'view ' ? $ share ->getNodeId () : null ;
246+ $ tableId = $ share ->getNodeType () === 'table ' ? $ share ->getNodeId () : null ;
247+
248+ if ($ viewId === null && $ tableId === null ) {
249+ throw new InternalError ('Cannot delete row without table or view provided ' );
250+ }
251+
252+ $ row = $ this ->rowService ->delete ($ rowId , $ viewId , '' , $ tableId );
253+ return new DataResponse ($ this ->rowService ->formatRowsForPublicShare ([$ row ])[0 ]);
254+ } catch (PermissionError $ e ) {
255+ return $ this ->handlePermissionError ($ e );
256+ } catch (NotFoundError $ e ) {
257+ return $ this ->handleNotFoundError ($ e );
258+ } catch (InternalError |\Exception $ e ) {
259+ return $ this ->handleError ($ e );
260+ }
261+ }
93262}
0 commit comments