Commit Graph
603 Commits
Author SHA1 Message Date
Dominik Schmidt 5807eea186 feat(graph): expose @microsoft.graph.downloadUrl and /content on driveItems
Populates @microsoft.graph.downloadUrl on file driveItems when requested
via $select and implements GET .../items/{item-id}/content as a 302 to
the same URL: a by-id WebDAV URL signed with OC_URL_SIGNING_SECRET,
verified by the proxy, valid for 30 minutes. Folders answer 404 on
/content and never carry the annotation.

The annotation is available on the driveItem stat, the children and
root children listings and the share jail item endpoint.
2026-09-07 12:59:50 +02:00
Dominik Schmidt 0459149e0c style(graph): gofmt import order 2026-09-07 12:59:08 +02:00
Dominik Schmidt 13da9331f2 refactor(graph): use BaseGraphService.publicBaseURL consistently
drive.WebUrl, driveItem.WebUrl and the public share link WebUrl all
derive from the same config value (graph.spaces.webdav_base), but only
driveItem.WebUrl used the pre-parsed BaseGraphService.publicBaseURL.
The other two re-parsed the config on every call.

Add a webURLForResource method on BaseGraphService for the /f/<id> URLs
(used twice, with a *string return matching the libregraph DriveItem
field shape), and inline g.publicBaseURL for the single /s/<token>
share-link case. Convert cs3ResourceToDriveItem and formatDriveItems
from free functions into BaseGraphService methods so they pick up
logger and publicBaseURL from the receiver. This also aligns them with
the surrounding code: BaseGraphService already exposes ~15 similar
methods, so the two free functions were the odd ones out.

Net: all three WebUrls are now constructed from a single pre-parsed
URL, and the (g.logger, g.publicBaseURL) plumbing at 7 call sites
disappears.
2026-09-07 12:59:08 +02:00
Dominik Schmidt 6231a870d5 feat(graph): expand thumbnails on driveItems
$expand=thumbnails was only honored by sharedByMe and sharedWithMe. The
driveItem stat, the children listing and the root children listing now
honor it as well, so a client that lists a folder learns which items have
a preview instead of guessing from the mime type.

The thumbnails are set from the resource info the listing already has, so
a later preview check that needs more than the mime type has a single
place to sit. The two share listings carry driveItems only, they keep
matching on the mime type but share the url building.
2026-09-06 23:51:35 +02:00
Dominik Schmidt bafbc88a40 graph: expose lockInfo on driveItems 2026-09-03 17:52:13 +02:00
Dominik Schmidt aa968ec898 graph: expose @libre.graph.shareTypes on driveItems 2026-09-03 16:59:29 +02:00
Dominik Schmidt 61037cc22f Merge pull request #3202 from opencloud-eu/feat/search-live-photo-facet
feat(search): live photo facet
2026-09-03 11:42:28 +02:00
Jörn Friedrich Dreyer 993265b64e Merge pull request #3445 from opencloud-eu/feat/graph-expand-children
feat: support $expand=children on the driveItem endpoint
2026-09-03 09:35:05 +02:00
Dominik Schmidt 81b0df1ad4 feat(search): live photo facet 2026-09-03 03:34:33 +02:00
Dominik Schmidt a2050d1fb9 feat(search): index and expose the motion photo facet 2026-09-03 00:31:40 +02:00
Dominik Schmidt 0750884597 perf: check the resource type before parsing the query 2026-09-01 20:04:22 +02:00
Dominik Schmidt aff81159a5 chore: drop the listDriveItemChildren comment 2026-09-01 20:01:54 +02:00
Dominik Schmidt 701d6fea17 chore: trim comments 2026-09-01 20:01:06 +02:00
Dominik Schmidt 74dd57d500 refactor: let formatDriveItems return values so children needs no copy 2026-09-01 19:59:51 +02:00
Dominik Schmidt b95e341f9c feat: support $expand=children on the driveItem endpoint 2026-09-01 19:55:14 +02:00
Dominik Schmidt 727c986de8 feat(search): index and expose the video facet 2026-09-01 16:26:01 +02:00
Dominik Schmidt f60e2e52e5 Merge pull request #3437 from opencloud-eu/feat/driveitem-pending-operations
graph: expose pendingOperations on driveItems
2026-09-01 15:35:24 +02:00
Pascal Bleser 249d105d27 Merge pull request #3293 from pbleser-oc/chore/#1312-graph-event-handler-split
chore(graph): disable HTTP or eventhandlers by configuration
2026-09-01 14:31:24 +02:00
Dominik Schmidt 000c99c63b graph: expose pendingOperations on driveItems 2026-09-01 14:05:18 +02:00
Pascal Bleser e4365320de chore(graph): use metrics tools introduced in 8821053ff8
* introduce a fix in the metrics tools introduced with 8821053ff8 in
    order to deal with a struct that has fields that are not exported
    (as is the case here)

  * introduce a func in the toplevel metrics package that registers a
    single metric, as that needs to be done explicitly for unexported
    ones

  * in the graph service, use RegisterAll and BuildInfo from the
    toplevel metrics package, as introduced with 8821053ff8
2026-09-01 10:57:54 +02:00
Pascal Bleser 5b72318493 chore(graph): add metrics for HTTP API and LDAP
Introducing gowrap as a build-time tool to generate interface delegate
structs from templates:

 * added as a 'make go-generate' target in services/graph,
 * added as a build-time dependency in .bingo/

Introduce an LDAP client abstraction interface to be able to wrap the
go-ldap client API with metrics transparently (and possibly hooks and
such in the future), in order to use delegation patterns to measure the
time LDAP (client) operations take to finish, as well as to track their
results (success, failure, not-found).

Has two implementations that are generated using gowrap:

* a go-ldap adapter implementation that directly delegates to a go-ldap
  connection
* a time measuring and metrics collecting implementation that delegates
  to another LdapClient

The metrics collecting one is disabled by default, can be enabled with
GRAPH_LDAP_METRICS_DISABLE=false

It collects durations of outbound LDAP client operations into a histogram, as
well as the number of concurrent outbound LDAP operations in a gauge (via an
atomic int and a gauge function, as that performs best).

Add an HTTP middleware that measures how long Graph HTTP API requests
take, storing taken time into a histogram along with labels for

 * method,
 * path pattern (from the chi routes),
 * Graph API version prefix,
 * Graph API resource name,
 * and the resulting status code.

It also tracks the number of concurrent inbound Graph API HTTP requests
using a gauge (also using an atomic int and a gauge function).

Disabled by default, can be enabled with
GRAPH_HTTP_METRICS_DISABLE=false

Add Backend and EducationBackend delegate implementations that measure
execution time on the level of the higher API call operations there
(CreateUser, DeleteUser, ..., CreateSchool, ...), generated using
gowrap.

Disabled by default, can be enabled with
GRAPH_IDENTITY_BACKEND_METRICS_DISABLE=false

Also added a small k6 script to produce some read-only load on the Graph
API, for a casual test of the metrics, as well as k6 in mise.toml.

Make an internal changes to how singular LDAP entry searches work in the LDAP
identity backends:

 * check whether searches for a singular entry returns more than one
   result, in which case a new error TooManyResults is returned, instead
   of leaving that undetected, blindly taking the first result, and
   potentially risking data inconsistencies

Improve the loggers in identity backends by adding attributes for their
request targets (Reva gateway address or LDAP URI, respectively).

Also add a "backend" attribute for all Graph API logs (set to "ldap" or
"cs3"), to help debug potential issues, and remove them from all the logger
debug calls at the beginning of each LDAP-related function as those should
really be part of the logger and set beforehand.

The LDAP identity backend logger also has two new attributes to help
debugging with logs:

 * write (bool): whether write operations are enabled
 * refint (bool): whether refint is enabled or not

Also adds a dedicated counter metric for user password change operations.

Minor campfire improvements:

 * add a constructor func for the CS3 backend

 * add a constructor func for the LDAP backend

 * in the LDAP identity backend, in searchLDAPEntryByFilter (used by all
   search/get public functions), errors that occur when performing LDAP
   SEARCH operations were blindly mapped to a ItemNotFound error,
   instead of being analyzed as it could be caused by a technical error

 * in the requireadmin middleware, add debug logging to explain why a
   request is denied

 * when an LDAP password change fails because the user entry was not
   found in LDAP, we now have a log message that tracks that
2026-09-01 10:57:47 +02:00
Pascal Bleser e8cf677353 chore(graph): disable HTTP or eventhandlers by configuration
In the scope of the broader issue #1312, this PR deals with performing
those changes for the `graph` service, namely to add the ability to
disable the HTTP API or to disable the events API handler by
configuration.

It also adds metrics for the events processing, and tests for the events
processing.

The previous implementation was combining the HTTP server service and
the events consumption, which is why this PR refactors the composition
of those services:

 * the event consumption has been moved into its own service
 * the identity.Backend is created beforehand, and then injected as a
   collaborator in both the HTTP service as well as the event consumer
   service

It also adds metrics, mainly for the event processing.

To encourage re-use in latter implementations and changes, it also
introduces two top-level package changes:

 * internal/eventstest/events_test_helpers: contains a TestBus
   implementation to unit-test event consumers without NATS
 * internal/metricstest/metrics_test_helpers: contains assertion
   functions to test Prometheus metrics
2026-09-01 10:57:26 +02:00
Dominik Schmidt 394b0fdc45 graph: expose @libre.graph.permissions.actions.allowedValues on driveItems
Opt-in via $select, on GetDriveItem and the root children listing.
2026-09-01 10:21:50 +02:00
Dominik Schmidt 11d8b8a382 graph: expose @libre.graph.tags on driveItems 2026-09-01 10:21:50 +02:00
Dominik Schmidt f0515bb28c graph: expose @libre.graph.me.following on driveItems 2026-09-01 10:21:50 +02:00
Dominik Schmidt e78cad1cbe refactor: reflection-based search mapping
Build the bleve and OpenSearch index mappings from the Go struct via
reflection (json tags + per-field overrides) instead of hand-rolled
mappings and hit deserializers. New mapping package: BleveBuildMapping,
OpenSearchBuildMapping, Deserialize[T], PrepareForIndex; field decoding is
fail-soft. Mtime is typed as a date so mtime ranges are chronological on
both backends. Route CS3 facet parsing through mapping.DeserializeStringMap.

The any-valued (bleve hit) and string-valued (CS3 metadata) deserializers
share one generic fillStruct walker with a per-value setLeaf callback.
2026-08-31 13:40:42 +02:00
Jannik Stehle 5b2529602f feat(graph): add LibreGraphContentType on drive 2026-08-20 09:03:56 +02:00
Florian Schade 2e5dd7b5ef Merge pull request #3297 from fschade/fix-mention-notification-review
fix(collaboration): harden the mention notification endpoint
2026-08-18 17:57:04 +02:00
Florian Schade bb8e185fbd fix(graph): use authResponse token exclusively 2026-08-18 15:03:57 +02:00
Florian Schade 99b01b0734 refactor(graph): let the cs3 mapper answer the statuses the handler does not name 2026-08-18 11:48:59 +02:00
Florian Schade 516734b18a fix(graph): map the cs3 status of a mention to the matching http error 2026-08-18 10:35:02 +02:00
Florian Schade bbee2b7433 fix: restructure call order 2026-08-18 09:40:01 +02:00
Alex a3c7b2dbb3 feat: update space template image (#3324)
* feat: update space template image

* skip test

* reduce asset size
2026-08-18 09:14:20 +02:00
Florian Schade 93d66a0f37 fix(graph): answer dropped mentions with 202 to prevent access probing 2026-08-17 15:48:00 +02:00
Florian Schade 8b922127b8 feat: move the collaboration mentioning api to graph 2026-08-17 15:44:04 +02:00
Dominik Schmidt 1f51bad9d1 refactor(graph): scope colon-path middleware to /drives/{driveID}
Addresses review feedback: a sub-router middleware can re-route after all,
as long as it rewrites chi.RouteContext().RoutePath instead of r.URL.Path.
Once chi has descended into a sub-router its routeHTTP matches against
rctx.RoutePath and ignores r.URL.Path, which is why the earlier top-level
registration was thought to be required.

Move ResolveGraphPath off the top-level mux.Use and attach it to the
/drives/{driveID} sub-routers (v1.0 + v1beta1). It now reads driveID from
chi.URLParam and matches against RoutePath (the part below the drive), so
the regexes drop the version + drive prefix entirely.

RoutePath carries the percent-encoded wire form (Graph.ServeHTTP sets
RawPath), so the captured driveID/itemID/path are PathUnescape'd exactly
once - reproducing the decoded r.URL.Path a normal handler would see,
without the previous RawPath/EscapedPath workaround. r.URL.Path is now
left untouched; only chi's internal RoutePath is rewritten.

Tests are reworked to drive requests through a chi router mirroring the
production nesting (including the Graph.ServeHTTP RawPath behavior), so
chi's sub-router middleware ordering, RoutePath encoding and param
round-trip are all covered indirectly: a chi upgrade that changes any of
them fails these tests instead of silently breaking colon-path lookups.
Adds explicit coverage for percent-decoding (%20, %252F) and the `$`/`!`
sub-delimiter id round-trip.
2026-07-01 17:44:31 +02:00
Dominik Schmidt 0b373817a8 feat(graph): add MS Graph colon-syntax path lookup middleware
Adds a chi middleware that detects MS Graph colon-syntax URLs and rewrites
them to the canonical /items/{itemID}/... form before chi performs route
matching. Existing handlers, routes, and GetDriveAndItemIDParam stay
unchanged.

Two URL shapes are recognized at both /v1.0 and /v1beta1:

  /drives/{driveID}/root:/<path>[:/<suffix>][:]
  /drives/{driveID}/items/{itemID}:/<relativePath>[:/<suffix>][:]

Path resolution runs as the request user via CS3 Stat. Both NOT_FOUND and
PERMISSION_DENIED collapse to a 404 response so existence isn't disclosed
to unauthorized callers. URLs without colon syntax fast-path through with
a single substring check. The original URL is stashed in request context
under OriginalPathContextKey for downstream tracing/logging.

The middleware is registered as a top-level mux.Use so it runs before any
route matching: chi middleware on a sub-router runs after the prefix is
matched but cannot redirect to a different leaf route. Top-level
middleware lets URL rewriting actually re-route the request.

Tests cover regex matching across versions, all rewrite variants
(root/items anchored, with/without suffix, with/without trailing colon,
deep paths), NOT_FOUND -> 404, PERMISSION_DENIED -> 404 (security: no
existence disclosure), and original-URL preservation in request context.
2026-07-01 17:44:31 +02:00
Ralf Haferkamp 99d80f30a9 fix: Status codes for Space Disable/Delete
Allow a "permission denied error" from reva to bubble up to the client.
Reva was fixed to return "permission denied" only when the space to be
delete can actually be listed by the user. Other wise it will return
"not found". See reva commit 1bf72cb76394671f373e87f15f23f978cf41ab08.

So when a user with the 'can manage' role tries to purge an already
disabled space it will now get "Forbidden" status instead of a "Not
found".

Also fixes the expected status codes in the tests.
2026-06-22 11:06:26 +02:00
Ralf Haferkamp d163c8ed29 fix(graph): translate sharing roles consitently
GetRoleDefinition/s does now handle l10n correctly. Previsouly it just
returned the non-localized string. What made things worse was that
ListPermissions() mutated global list of available roles and replaced
some strings with translated values depending on the `accept-language`
header. Which resulted in GetRoleDefinition returning results in mixed
localization depending on who/what called ListPermissions before.

Fixes: #2800
2026-06-11 14:31:44 +02:00
Christian Richter 0351adfe6b change logger level
Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2026-05-20 14:14:00 +02:00
Ralf Haferkamp f056326c4c Merge remote-tracking branch 'origin/main' into feature/guest-links 2026-05-13 14:35:54 +02:00
Jörn Friedrich Dreyer 5d7bfc9033 delete unused constants
Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
2026-05-13 10:54:00 +02:00
Dominik Schmidt a75d89d1b0 feat(graph): populate driveItem.webUrl per Libre Graph spec
The Libre Graph spec declares webUrl on driveItem but
cs3ResourceToDriveItem never set it. Build the /f/<resource-id>
permalink off the configured public base URL (same source drives.go
reads for drive.webUrl) and parse it once at service construction
so callers can use it as a plain field.
2026-05-12 15:28:10 +02:00
Ralf Haferkamp 173485cf44 Merge remote-tracking branch 'origin/main' into feature/guest-links 2026-04-29 10:24:57 +02:00
André Duffeck e9e195789d Adapt to changes in reva/cs3apis 2026-04-24 14:49:11 +02:00
Ralf Haferkamp ec8733ac52 graph: use share manager for managing space permissions
This gets us rid of quite a bit of special casing for space permission.
Also provides us with "real" permission IDs instead of those faked
"u:<userid>" ones.
2026-04-23 17:07:00 +02:00
Ralf Haferkamp fad0cc4828 Use filter to avoid including space membership in the sharedWithMe response 2026-04-23 17:07:00 +02:00
Florian Schade 288e67cc39 chore: replace interface with any 2026-04-23 09:31:11 +02:00
Ralf Haferkamp e2f322791a fix(graph): sort drive in "natural" order
Instead of doing a lexical sort we sort the drive/space in a more
"natural" order so that e.g. "Space 2" is sorted before "Space 10".

Related: https://github.com/opencloud-eu/web/issues/2430
2026-04-23 08:44:13 +02:00
André Duffeck bfba4ec671 Render the followed drive item after following it according to the spec 2026-03-13 09:38:28 +01:00