* Read feature status from Billing.Feature instead of %Site{}
This commit changes data attributes passed to React. Previously the
controller read feature statuses directly from the %Site{} schema. The
Billing.Feature context is aware of the user plan and the features
available.
* Limit funnels internal API based on site owner plan
* Limit props internal API based on site owner plan
* Use site factory in QueryTest
* Limit custom property filter based on site owner plan
* Limit revenue goals queries based on site owner plan
* Update styling for Choose Plan page
* Make it look good on mobile
* Update tests
* Remove unnecessary assign
* Optimize for dark mode
* Change order or interval picker and slider on mobile
* Format
---------
Co-authored-by: RobertJoonas <56999674+RobertJoonas@users.noreply.github.com>
* Add SSO link with signed JWT token
* Falls back to Nolt URL without SSO if token cannot be generated
* Add profile image (gravatar) to Nolt SSO link
* Improve navbar dropdown
* Add 'contact support' link to nav dropdown
* Add CSS rule to prevent horizontal jumps
* Dark mode styling
* Close dropdown when link is clicked
* Clarify links in dropdown
* Clarify CSS comment
* Use Alpine.data() over window
* Rename suggestions_dropdown -> combo-box
* Mix format
* Make logout link look good on dark mode
* Use proxy for gravatar
* Do not use Gravatar proxy in self-hosted
* Changelog
* Add Github Repo link to nav dropdown
* Make dialyzer happy
* Add proxy for Gravatar
* Update assets/css/app.css
Co-authored-by: hq1 <hq@mtod.org>
* Update lib/plausible_web/controllers/avatar_controller.ex
Co-authored-by: hq1 <hq@mtod.org>
* Fix alpine <> Liveview integration
---------
Co-authored-by: hq1 <hq@mtod.org>
* Refactor email verification codes generation to avoid predictability
* Improve `Site.Memberships.any?` slightly
* Update tests
* Fix seeds
* Use `expired?` predicate for checking verification code validity in tests
* Store verification code as string in database to avoid unnecessary int casting
* Include ApiKey functions in Auth context
* Make feature notice work without %Site{}
Previously the extra feature notice required a %Site{} in order to check
the owner plan. However, not every feature is scoped by site, for
example the Stats API. For features like this, a %User{} is required,
and not a %Site{}.
This commit replaces the `:site` param with `:billable_user`, which is
common to both site and user-scoped features.
* Add stats_api to the list of extra features
* Limit API Key creation based on user plan
This pull request implements limits to funnels, revenue goals and custom props based on the site owner plan. It extends the current "premium feature" notice to account for the new plans, trials and the on-going private preview. Stats API is not in the context of this pull request, but will be implemented likewise.
* Implement PoC for email reverification flow on update
* Improve user settings form and email change validation
* Expose `previous_email` in Kaffy CRM
* Improve plugs setup and remove dead action from AuthController
* Fix seeds
* Extract predicate query functions from AuthController
* Add tests
* Update CHANGELOG.md
* Rename `has_any_sites?` to `Memberships.any?` and `has_any_memberships?`
* Improve flash message on cancelling email change
* Cover one more test case for email update
* rename enterprise?/1 function
* change link text to Upgrade when subscription deleted
* extract paddle_button and paddle_script components
* create a new upgrade-to-enterprise-plan page
* extract upgrade_link component
* rename function
* link to enterprise plan upgrade page from settings
...if the user has an enterprise plan configured
* fetch enterprise plan price on the new page
* add change_enterprise_plan functionality on the new page
* render existing change_enterprise_plan_contact_us.html
...when subscribed to latest configured enterprise plan
* rename vars and extract resumable? fn
* remove dead billing route
* small test refactor: extract convenience fn
* add tests for...
...restricting paused and past_due subscription access to the new
enterprise plan page.
1. redirect to /settings from the controller action
2. hiding the change-plan link from the user settings
* implement redirect to /settings
* hide the enterprise upgrade/change-plan link
* add tests for a deleted enterprise subscription
* plug in the new controller action and delete dead code
* optimize for dark mode
* fix compile warning
* credo fix
* display N/A instead of crash when price nil
* change subscription.status type to Ecto.Enum
Also, create a new `Subscription.Status` module that exposes macros to
return the used atom values (prevent typos at compiletime).
* fix bug (@conn not available anymore)
* use Routes.billing_path where applicable
* add a status() type
* silence credo
* refactor suggestion from review
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
* Remove the __using__ macro from Subscription.Status
... instead be explicit about requires and aliases and also order
the use, import, require, and alias clauses according to
https://github.com/christopheradams/elixir_style_guide#module-attribute-ordering
* drop the virtual Enteprise 'price_per_interval' field
* apply review suggestion to make the code more DRY
* use dot syntax to fetch current user in new controller actions
* fix formatting
---------
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
* Make FixBrokenGoals migration idempotent
The migration in question was renamed in order to fix order of executing migrations when run
from the ground up (via https://github.com/plausible/analytics/pull/3378).
As a side effect, it's executed again on databases that had it applied earlier, with
a different timestamp prefix.
As this migration is safe to run multiple times, it was modified to make forward
migration work gracefully when constraint already exists.
* Add `pending-migrations.sh` release script
* add a new upgrade page liveview behind a FF
* Create plans_v4.json file
* Add the upgrade page UI template and some basic functionalities
* different content based on subscription plan existing or not
* pageview slider
* monthly/yearly switch
* fix tests
* split into 2 separate functions
* rename variables
* implement volume slider + read default interval/volume from plan
* organize choose-plan.ex better
* remove unused vars from tests
* make monthly_cost and yearly_cost nil by default
The actual prices for all plans are stored in Paddle. We don't need to
keep the duplicates in the JSON files.
* add fetch_prices/1 to PaddleApi
* make v4 business ID's differ from growth ones
* render actual price information from plans
...and make the prices in both growth and business plan boxes change
dynamically when the pageview slider or interval is changed.
* highlight current subscription plan box
* add test describe block for business tier subscription
* connect to live socket only on the specific LV page using focus.html
* only wrap the input slider inside the form
* little readability improvement
* add v4 team_member_limits (after rebase with master)
* extract monthly_quota_box function in user_settings
When the business_tier FF is enabled, this section is different and
links to the new upgrade page.
* document subscription statuses
* change _notice.html.eex to .heex
* extract subscription status notice components
* add failed payment notices to upgrade page
* create class_of_element/2 convenience function for testing
* add cancel_subscription mix task
* implement checkout buttons
* mix format
* get all available plans with prices through plans.ex
* use more suitable function for fetching usage
* avoid double db lookups on mount
* rename variable
* separate functions for getting plan by product_id vs subscription
* separate subscription status docs into context module
* consider cancelled subscriptions
* default volume by usage if no subscription plan
* add enterprise-level volume option to slider
* optimize for darkmode
* UI improvements
* display 2 months free notice for yearly billing
* VAT excluded notice
* note about having a business subscription in user settings
* make the page pop and fit plans on screen on first render
* optimize for mobile and remove background containers
* change default price tag to simply 'N/A'
* fix tests
* Change Paddle.js integration to use JavaScript directly
* rename many variables
* allow users on v1 and v2 plan subscribe to 20M and 50M tiers
* add a test for two months free label
* make it work with a free_10k subscription
* small test improvement and formatting
* change other upgrade link in user settings if FF enabled
* dialyzer
* fix typo
* add test for free_10k user
* silence credo
* mix format
* credo - add moduledoc
* credo - another moduledoc
* handle calls to sentry on the api level
* refactor getting regular subscription plan for LiveView
* post review code style tweaks
* remove unused aliases
* credo - add @moduledoc false to Subscriptions
* crash in cancel_subscription task when Repo update fails
* readability improvements (review suggestions)
* add comment about 'external_resource' module attr
---------
Co-authored-by: Vinicius Brasil <vini@hey.com>
This change addresses two problems:
* controller action crashing missing "token" param - it's handled gracefully
now and will not pollute Sentry anymore with http://sentry.plausible.io/organizations/sentry/issues/4319
* LiveView receives email extracted from token on initial page load instead
of reverifying token on every re-mount (which can happen when somebody
leaves form open for an extended period of time; rare but happens and
needlessly pollutes Sentry as well)
* Make membership creation and role updates more explicit in terms of changesets
* Extract invitation accept flow logic and refactor it slightly
* Improve acceptation logic
* Update moduledoc
* Improve SiteLocker API and add typespecs
* Stop naming function not returning a boolean like a predicate
* Refactor rest of invitation actions and safeguard against rogue requests
* Update code docs slightly
* Extend `Billing.check_needs_update/1` tests
* Parametrize selfhost flag and toggle SiteLocker logic on it
* Add tests for newly extracted services
* Add test case and a fix for locking site on grace period ended
* Make invitation controller tests async as there's no more env patching
* Add test cases for self-invites and fix one bug
* Add and refactor tests for rejecting and removing invitations
* Prevent issuing ownership transfer to existing owner
* Improve name of the test
* Improve `Billing.check_needs_to_upgrade/1` return value
* Improve `Billing.SiteLocker.update_sites_for/1` and its tests
* Fix typos
Co-authored-by: hq1 <hq@mtod.org>
* Make invitation removal and rejection resilient to races
---------
Co-authored-by: hq1 <hq@mtod.org>
* Update depenedencies: OpenAPISpex + cursor based pagination
* Update formatter config
* Add internal server error implementation
* Test errors
* Implement pagination interface
* Implement Plugins API module macros
* Implement Public API base URI
(to be used with path helpers once called from within
forwarded router's scope)
* Implement OpenAPI specs + schemas
* Implement Shared Links context module
* Add pagination and error views
* Add Shared Link view
* Implement Shared Link controller
* Expose SharedLink.t() spec
* Implement separate router for the Plugins API
* Update moduledocs
* Always wrap resource objects with `data`
* Update moduledoc
* Use https://github.com/open-api-spex/open_api_spex/pull/425
due to https://github.com/open-api-spex/open_api_spex/issues/92
* Rely on BASE_URL for swagger-ui server definition
* Fixup goals migration
* Migrate broken goals before deleting dupes
* Remove bypassing test rate limiting for which there's none anyway
* Move the context module under `Plausible.` namespace
* Bring back conn assignment to PluginsAPICase template
* Update test/plausible_web/plugins/api/controllers/shared_links_test.exs
Co-authored-by: Uku Taht <Uku.taht@gmail.com>
* Update renamed aliases
* Seed static token for development purposes
* Delegate Plugins API 500s to a familiar shape
* Simplify with statement
---------
Co-authored-by: Uku Taht <Uku.taht@gmail.com>
* Implement Plugins API Token schema
* Work with domain change grace period
* Do not cast internal data, extend schema with hints
* Implement Plugins API authorization
* Test no authorization header passed
* Preload authorized site
* Fixup typespecs
* Add zxcvbn dependency
* Change password length range requirement from 6-64 to 12-128
* Reimplement register form in LV
* Implement server-side check for password strength
* Add rudimentary strength meter
* Make password input with strength a separate component and improve it
* Fix existing tests to provide strong enough password
* Apply formatting
* Replace existing registration form with new one
* Hide built-in label in `.input` component when none provided
* Crop password to first 32 chars for analysis by zxcvbn
* Add tests for new form components
* Integrate hCaptcha into LV
* Fix existing AuthController tests
* Add tests for Live.RegisterForm
* Hide strength meter when password input is empty
* Randomize client IP in headers during tests to avoid hitting rate limit
* Apply auxilliary formatting fixes to AuthController
* Integrate registration from invitation into LV registration logic
* Fix existing password set and reset forms
* Make `password_length_hint` component more customizable
* Optimize `Auth.User.set_password/2`
* Remove unnecessary attribute from registration form
* Move password set and reset forms to LV
* Add tests for SetPasswordForm LV component
* Add tests for password checks in `Auth.User`
* Document code a bit
* Implement simpler approach to hCaptcha integration
* Update CHANGELOG.md
* Improve consistency of color scheme
* Introduce debounce across all text inputs in registration and password forms
* Fix email input background in register form
* Ensure only single error is rendered for empty password confirmation case
* Remove `/password` form entirely in favor of preferred password reset
* Remove unnecessary `router` option from `live_render` calls
* Make expensive assigns in LV with `assign_new` (h/t @aerosol)
* Accept passwords longer than 32 bytes uniformly as very strong
* Avoid displaying blank error side by side with weak password error
* Make register actions handle errors gracefully
* Render only a single piece of feedback to reduce noise
* Make register and password reset forms pw manager friendly (h/t @cnkk)
* Move registration forms to live routes
* Delete no longer used deadviews
* Adjust registration form in accordance to changes in #3290
* Reintroduce dogfood page path for invitation form from #3290
* Use alternative approach to submitting plausible metrics from LV form
* Rename metrics events and extend tests to account for them
* Adding a note about WP plugin
* Make it pretty
* Add component for link in new tab
* Adjust link styling for dark mode
* Update Subscription.free (for testing purposes)
* More natural interface for syled_link
* Use <.styled_link> helper in change_domain.html.heex
* Mix format
* Fix warning
* Fix credo warning
---------
Co-authored-by: Uku Taht <uku.taht@gmail.com>
* Enforce goals unique
* Remove unnecessary alias
* Skip tests that can no longer run anymore
To run, make sure the migration from
priv/repo/migrations/20230914071245_goals_unique.exs
is rolled back.
* Use separate transactions for the migration
* Update priv/repo/migrations/20230914071245_goals_unique.exs
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
---------
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
* Add `RewriteFunnelDupes` data fix
To rewrite funnels referencing goals whose names
are the same. This enables us to enforce all goals
within the site unique later on.
* Credo
* Update priv/data_migrations/FunnelDupeGoals/sql/list-funnels-with-dupe-goal-ids.sql.eex
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
* Revert unrelated changes
* Remove dead code
* Update lib/plausible/data_migration/rewrite_funnel_dupes.ex
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
* Update lib/plausible/data_migration/rewrite_funnel_dupes.ex
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
---------
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
Ensures that only one workflow is running per branch at a time.
If you are working on a branch and push several commits in succession, any workflows in progress will be cancelled and only the last one will run.