=== left&right Drive Portal ===
Contributors: leftandright
Tags: google drive, client area, documents, file manager, download
Requires at least: 6.2
Tested up to: 6.9
Requires PHP: 7.4
Stable tag: 1.0.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Private document area built on Google Drive: authorised WordPress users browse, search and download the shared files, with no public links.

== Description ==

left&right Drive Portal connects one or more Google Drive folders to WordPress
and serves them as a private area. Access is governed by WordPress roles: every
rule links a role to a Drive folder, and a user only sees the folders that
belong to them.

Main features:

* Service account authentication: no Google sign in window, no consent screen to
  publish, nothing that expires after a few days
* WordPress role to Drive folder mapping, with several rules per role
* Folder browsing with breadcrumb, list view and grid view
* File name search limited to the assigned folder
* Image and PDF preview
* Google Docs, Sheets and Slides exported on the fly: Office formats for
  download, PDF for preview
* Streaming download through WordPress: the Google URL never reaches the browser
* Thumbnails generated by Google for images
* Configurable cache to reduce API calls
* Folder picker built into the admin page
* Frontend template overridable from the theme

== Why a service account ==

Reading someone's Drive with the usual "Sign in with Google" flow needs the
`drive.readonly` scope, which Google classifies as restricted: a plugin
distributed to other people would need verification plus a paid security
assessment every year, and until that is granted the refresh tokens expire after
seven days, which means every client site would break once a week.

A service account avoids all of it. The client creates a technical identity in
their own Google Cloud project, shares one Drive folder with its address, and
the plugin sees that folder and nothing else. There is no consent screen, no
verification, no expiry, and the access is narrower than the OAuth flow would
have been.

== Free version, trial and Pro ==

There is a single package. After installation the plugin runs in the free
version; the Pro features stay visible in the admin but switched off, with a
"Pro" label next to them.

Free version:

* Service account connection, read-only
* One role to folder rule
* Folder browsing with breadcrumb
* Protected streaming download through WordPress
* List view, light theme

Pro features:

* Unlimited role to folder rules
* File search
* Image and PDF preview, thumbnails generated by Google
* Grid view
* View only: downloads can be switched off per rule
* Dark and auto theme, custom portal colour
* Configurable cache duration

Trial: from the "Drive Documents" page you can start a 7-day Pro trial, with no
credit card and no automatic renewal. When the trial ends the portal keeps
working in the free version: no document is lost and the Pro settings stay
stored, ready to switch back on with a licence. The trial can be used once per
site and does not restart if the plugin is reinstalled.

Licence: paste the key on the plugin page and press Activate. Validation runs
against the licence server set by the LRGDP_LICENSE_ENDPOINT constant or the
`lrgdp_license_endpoint` filter. If the server cannot be reached the licence
stays valid for a 14-day grace period, so a hosting network problem never
switches off a site that has already been paid for.

The limits are commercial only: no security check depends on the licence state.
Authentication, role, nonce and folder ownership are verified exactly the same
way in the free version and in the Pro version.

== Security ==

The plugin does not generate Google shared links. Every file request goes
through WordPress, which verifies authentication, role, nonce and that the file
belongs to the allowed folder.

On Drive there are no paths: files and folders are identified by opaque IDs, and
an ID is as guessable as a path. For that reason every request walks the chain
of parents of the requested item up to the folder assigned to the role, and is
refused when the item does not descend from it. The walk is cached, so it costs
one call per item at most.

Other security decisions worth knowing:

* A full resolution preview is equivalent to a download: a "save as" is enough.
  For that reason, when a rule has downloads switched off, images are served as
  reduced versions generated by Google and PDF preview is not offered.
* SVG and HTML files are never shown inline, because they can carry executable
  code in the site origin. They stay downloadable as attachments.
* Inline delivery is limited to JPEG, PNG, GIF, WebP, BMP, TIFF and PDF. Every
  other format is forced to attachment, even if another plugin registered its
  MIME type.
* A rule without a folder is rejected on save: on Drive there is no account root
  to fall back to, so an empty rule would silently show nothing.
* The service account key is stored in its own option with autoload disabled, so
  it is not loaded on every request of the site.
* The page containing the shortcode declares DONOTCACHEPAGE and sends no-cache
  headers, because the output depends on the user. If you use a full page cache
  at proxy or CDN level, exclude the page there as well.
* File delivery goes through wp-admin/admin-post.php. If a hardening plugin
  blocks /wp-admin/ for non-administrative roles, add an exception for
  admin-post.php, otherwise browsing works but files do not open.

== Installation ==

1. Upload the `lr-drive-portal` folder to `/wp-content/plugins/`, or install
   the zip from Plugins > Add New > Upload plugin.
2. Activate the plugin.
3. Go to "Drive Documents" in the WordPress menu and follow the three steps on
   the page.

== Google service account setup ==

1. Open https://console.cloud.google.com and create a project, or pick an
   existing one.
2. APIs and services, Library: search for "Google Drive API" and press Enable.
3. IAM and admin, Service accounts: press Create service account, give it any
   name, confirm. No role needs to be granted.
4. Open the service account, Keys tab, Add key, Create new key, JSON. The file
   downloads to your computer.
5. Paste the content of that file into step 1 of the plugin page, or choose the
   file itself, and save.
6. The plugin shows the address of the service account, something like
   `name@project.iam.gserviceaccount.com`. Open the folder in Google Drive,
   press Share, paste that address and give it the Viewer role.
7. In step 3 press Browse: the shared folder appears, and can be assigned to a
   WordPress role.

Notes:

* Viewer is enough. The plugin never writes to Drive.
* Sharing the folder is enough for everything inside it, including subfolders
  and files added later.
* On Google Workspace an administrator can forbid sharing outside the domain. In
  that case create the service account in a project of the same organisation, or
  ask the administrator to allow that address.
* Shared drives work: share the drive, or a folder inside it, with the service
  account address.

== Shortcode ==

`[lr_drive_portal]`

Attributes:

* `root` - ID of the rule to show. If omitted it shows every folder the user can
  access.
* `view` - `list` (default) or `grid`. Grid is a Pro feature.
* `theme` - `light` (default), `dark` or `auto` (follows the visitor
  preferences). Dark and auto are Pro features.
* `title` - title shown in the coloured bar at the top of the portal.
* `subtitle` - line of text under the title.
* `height` - maximum height of the scrolling area, for example `600px`.

Example: `[lr_drive_portal view="grid" theme="auto" title="Project documents" subtitle="Updated from Google Drive" height="620px"]`

== Developer hooks ==

Filters:

* `lrgdp_user_roots` - alter the folders a user can access.
* `lrgdp_allow_file_access` - block access to a single file.
* `lrgdp_license_can` - alter the availability of a single Pro feature.
* `lrgdp_license_endpoint` - point to a different licence service.
* `lrgdp_pricing_url` - change the pricing page linked from the admin.

Actions:

* `lrgdp_file_accessed` - fired on every file access, useful for logging and
  audit trails.

Template: copy `templates/browser.php` to
`wp-content/themes/<theme>/lr-drive-portal/browser.php`.

== Frequently Asked Questions ==

= Do the files pass through my server? =
Yes. It is a deliberate choice: it is the only way to guarantee that a link does
not work outside the private area. Transfer happens in chunks, so PHP memory is
not saturated, but server bandwidth is used. The size limit is configurable in
the settings.

= What happens with Google Docs, Sheets and Slides? =
They have no downloadable content as they are, so the plugin exports them on the
fly: Word, Excel and PowerPoint formats for download, PDF for preview. Their
size is not known in advance, so the maximum download size does not apply to
them.

= Does switching downloads off really prevent getting the file? =
It reduces the surface a great deal but it is not absolute protection: anyone
who can see content on screen can photograph it. With downloads off the plugin
never delivers the original bytes (images are reduced, PDFs are not shown), so
the source file stays out of reach. Stricter requirements need DRM, which this
plugin does not implement.

= Why can I not see files I just added to Drive? =
The default cache lasts 5 minutes. Use the Refresh button in the file browser,
or shorten the cache duration in the settings.

= The folder does not appear in the Browse window =
Three usual causes: the sharing was done on a file instead of the folder, the
organisation forbids sharing outside the domain, or Google has not propagated it
yet. Press Clear cache and reload the page, then run the connection check in
step 1: it says exactly what Google answers.

= Does the connection expire? =
No. A service account key does not expire on its own. It stops working only if
it is deleted from the Google Cloud console, or if the folder is unshared.

== Installing on several client sites ==

Every client uses their own Google Cloud project and their own service account,
so nothing is shared between sites and no value has to be edited in the code.
The plugin page shows the address to share the folder with, with a copy button.

The connection check in step 1 runs real calls to Google and reports what comes
back, which is normally enough to tell a missing API, a key that was deleted and
a folder that was never shared apart from each other.

== Living with the site theme ==

The portal carries a reset that neutralises the global styles of the theme
inside its own container, so in most cases nothing needs to be done.

If the theme has a fixed header that stays above the content while scrolling, it
helps to give the portal its own scrolling area with the height attribute:

`[lr_drive_portal height="620px"]`

That way the search bar stays visible at the top of the portal and only the file
list scrolls, instead of ending up under the site header.

To change the look without modifying the plugin, the CSS variables are enough:

`.lrgdp-portal { --lrgdp-accent: #002b5c; --lrgdp-radius: 6px; }`

== Languages ==

The plugin ships in English, with an Italian translation in
`languages/lr-drive-portal-it_IT.po` and `.mo`.

== Changelog ==

= 1.0.0 =
* First release. Private document area on Google Drive, with the same structure
  and the same interface as left&right Dropbox Portal.
* Service account authentication: no consent screen, no Google verification, no
  seven-day token expiry.
* Containment check on every request: an item is served only if it descends from
  the folder assigned to the role.
* Google Docs, Sheets and Slides exported on the fly, Office for download and
  PDF for preview.
* Freemium: free version with one rule, 7-day Pro trial, licence activation with
  a 14-day grace period if the licence server cannot be reached.
