Skip to content

Conversation

@blizzz
Copy link
Member

@blizzz blizzz commented Dec 8, 2025

contributes to #67

  • modifies oc_tables_share structure with two columns, token and password
  • adds ShareOCSController with a route to create link shares
  • adds a PageController front route to display the link share
  • adds a ApiPublicColumnsController to retrieve columns for public
    links. It was not added to the existing ApiColumnsController, as it
    requires the userId of the logged-in user and I did not want to weaken
    this detail.
  • adds an abstract controller for columns with shared functionality and
    make ApiColumnsController extend it.
  • adds a PublicRowOCSController for retrieving rows through link shares
  • adds a ShareToken value object
  • adds a ShareControlMiddleware for share token and existance
    validation. It comes with the AssertShareToken attribute.
  • extends Share entity with ShareToken and Password properties
  • extends ShareMapper to find a share by the share token
  • extends ShareService with a method to easily create link shares
  • extends ResponseDefinitions with TablesPublicRow and
    TablesPublicColumn specs. Essentially tableIDs are not exposed and
    also user ids in lastEditBy and createdBy are not disclosed.
  • extends RowService and ColumnService with methods to return such ^
    formatted result arrays.
  • extends OpenAPI spec

Curl examples for added API endpoints

Create a share link without password

curl -u user:secret -X POST https://cloud.example.com/ocs/v2.php/apps/tables/api/2/tables/${TABLE_ID}/share -H "OCS-APIRequest: true"

fetch column information

curl -i https://cloud.example.com/ocs/v2.php/apps/tables/api/2/public/${SHARE_TOKEN}/columns -H "OCS-APIRequest: true"

fetch all rows

curl -i https://cloud.example.com/ocs/v2.php/apps/tables/api/2/public/${SHARE_TOKEN}/rows -H "OCS-APIRequest: true"

@blizzz blizzz added enhancement New feature or request 2. developing Work in progress labels Dec 8, 2025
@blizzz blizzz self-assigned this Dec 8, 2025
@github-project-automation github-project-automation bot moved this to 🧭 Planning evaluation (don't pick) in 📝 Office team Dec 8, 2025
@blizzz blizzz moved this from 🧭 Planning evaluation (don't pick) to 🏗️ In progress in 📝 Office team Dec 8, 2025
@blizzz blizzz force-pushed the enh/noid/link-share-biz branch 4 times, most recently from c331e92 to ec7bd73 Compare December 11, 2025 12:00
#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
#[FrontpageRoute(verb: 'GET', url: '/s/{token}')]
public function linkShare(string $token): TemplateResponse {
Util::addScript(Application::APP_ID, 'tables-main');
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@enjeck may keep this if new functionality goes into the main script, or otherwise we can change this if course and load a different one.

The share token is being provided via initialState a few lines below.

@blizzz blizzz force-pushed the enh/noid/link-share-biz branch 2 times, most recently from d0a78bc to 63b0a70 Compare December 11, 2025 20:31
- modifies oc_tables_share structure with two columns, token and password
- adds ShareOCSController with a route to create link shares
- adds a PageController front route to display the link share
- adds a ApiPublicColumnsController to retrieve columns for public
  links. It was not added to the existing ApiColumnsController, as it
  requires the userId of the logged-in user and I did not want to weaken
  this detail.
- adds an abstract controller for columns with shared functionality and
  make ApiColumnsController extend it.
- adds a PublicRowOCSController for retrieving rows through link shares
- adds a ShareToken value object
- adds a ShareControlMiddleware for share token and existance
  validation. It comes with the AssertShareToken attribute.
- extends Share entity with ShareToken and Password properties
- extends ShareMapper to find a share by the share token
- extends ShareService with a method to easily create link shares
- extends ResponseDefinitions with TablesPublicRow and
  TablesPublicColumn specs. Essentially tableIDs are not exposed and
  also user ids in lastEditBy and createdBy are not disclosed.
- extends RowService and ColumnService with methods to return such ^
  formatted result arrays.
- extends OpenAPI spec

Signed-off-by: Arthur Schiwon <[email protected]>
@blizzz blizzz force-pushed the enh/noid/link-share-biz branch from 63b0a70 to 9f86cfc Compare December 20, 2025 00:38
@blizzz blizzz added 3. to review Waiting for reviews and removed 2. developing Work in progress labels Dec 20, 2025
@blizzz blizzz marked this pull request as ready for review December 20, 2025 00:39
@blizzz blizzz requested a review from enjeck as a code owner December 20, 2025 00:39
@blizzz blizzz requested a review from a team December 20, 2025 00:47
$shareToken = new ShareToken($token);
$this->initialState->provideInitialState('shareToken', (string)$shareToken);

return new TemplateResponse(Application::APP_ID, 'main', [], TemplateResponse::RENDER_AS_GUEST);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be RENDER_AS_GUEST? Or RENDER_AS_PUBLIC?

$this->loadStyles();

$shareToken = new ShareToken($token);
$this->initialState->provideInitialState('shareToken', (string)$shareToken);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To properly load text editor so that rich text cells display properly, we need to add:

		if (class_exists(LoadEditor::class)) {
			$this->eventDispatcher->dispatchTyped(new LoadEditor());
		}

I already did at https://github.com/nextcloud/tables/pull/2236/changes#diff-70e5309fcd3311d771b3db9c93490ea270fd5894769093765ec37edb68e5dd9b

@enjeck enjeck mentioned this pull request Dec 28, 2025
2 tasks

/**
* @psalm-import-type TablesPublicColumn from ResponseDefinitions
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't use #[AssertShareToken] here too?

#[PublicPage]
#[AssertShareToken]
#[ApiRoute(verb: 'GET', url: '/api/2/public/{token}/rows', requirements: ['token' => '[a-zA-Z0-9]{16}'])]
#[OpenAPI]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since these are public, I imagine they are more prone to scraping and DoS? Do we want to throttle them?

public function formatRowsForPublicShare(array $rows): array {
return array_map(static function (Row2 $row): array {
$rowData = $row->jsonSerialize();
unset($rowData['tableId']);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we unset the tableId but not the column/row ids? What makes tableId more riskier

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3. to review Waiting for reviews enhancement New feature or request

Projects

Status: 🏗️ In progress

Development

Successfully merging this pull request may close these issues.

3 participants