* Revert "Revert "Move conversion_rate logic from elixir to clickhouse (#3887)"…"
This reverts commit 253fb5d67d.
* Fix issue with missing columns
The issue came from refactoring event:goal UNION ALL logic and trying to move
name select from first to last. If any other tables were joined, the incorrect
item would be used as an array index, causing this issue.
Added a relevant test.
* Separate out query building from pagination/execution logic.
* Refactor pageview_goals breakdown query, removing index column from results
* Remove zip_columns logic
* Use common pagination util
* Do everything in a single query for breakdowns for goals
* Order in DB
* Make sure column order is identical
* Calculate CR within the goal breakdown query
* Calculate CR for property breakdowns
* WIP: Calculate group CR
* CR with order_by
* Compatibility fix
* Import Ecto.Query and cleanup
* handle total_visitors the same way as add_percentage
* Handle conversion_rate in aggregate.ex
* Solve rebase fail
* Simplify maybe_add_group_conversion_rate
* Add conversion_rate defaults to 0 test
* Add test for conversion_rate should not be calculated with imported data (failing here and on master)
* Dont include imported data when breakdown by prop or goal
* Remove revenue_nils
* encode/decode date range in filenames
* Update lib/plausible/imported/csv_importer.ex
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
* Update lib/plausible/imported/csv_importer.ex
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
* drop unused functions
* send failure email if there is no data to export
* use PlausibleWeb.Email.mailer_email_from()
* ensure we get dates from minmax date query
---------
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
* ui
* fix redirect link
* improve make minio
* use implicit button form for csv export
* add exports_bucket helper
* read S3_EXPORTS_BUCKET
* supply s3_bucket in export_csv job args
* make plausible_minio use unprotected port
* move s3_csv_export queue to base queues
* Update lib/plausible_web/controllers/site_controller.ex
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
---------
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
* Reapply "Replace caching engine (#3878)" (#3883)
This reverts commit c5881cdc6d.
* Ensure hit rate is tracked on `get_or_store`
* Remove :wx and :observer
* Remove unused deps
* Use `:set` table type
* prevent division by 0 in merge_imported queries
* Revert "fix bounce_rate change bug (#3886)"
This reverts commit 6eef32a8ff.
After 02aa0b2, we can keep on assuming that bounce rate is always numeric.
* Implement LV date input using flatpickr
* Implement basics of GA4 import (very dirty WIP)
* Split Google HTTP API into UA and GA4 specific parts
* Add a quick way to record GA4 API responses
* Add first GA4 import fixtures with GA4 Data API responses
* Extract GA4 and UA specific logic form Google API
* Extract UA and GA4 specific actions to distinct controllers
* Add integration test for GA4 importer
* Update GA4 fixtures
* Test GA4 API
* Add debug logging and fix paginating through API results in in GA4 import
* Revert "Implement LV date input using flatpickr"
This reverts commit c696f8ee39d5702f27015c09a4f079ca124cc7bb.
* Fix note
* add metric validation + support in aggregate
* add a test ensuring comparison works
* disallow time_on_page with a goal filter
* Return time_on_page as `nil` from aggregate API
In case time_on_page cannot be calculated, we'll return it as `nil` from
the Stats API.
This is to make the behaviour consistent between breakdown and aggregate
endpoints. As for the UI, we'll still continue to report time_on_page as
0 - not changing any UI behaviour as discussed with Marko.
* add tests for time_on_page in event:page breakdown
* update changelog
* invalidate time_on_page with event:name filter
* add the ability to only query time_on_page in page breakdown
We'll need the visitors metric to get the list of pages to calculate the
time_on_page for.
* Dependencies: swap Cachex for ConCache
* Implement Cache adapter wrapping ConCache
* Implement cache stats tracker, for metrics
* Use Cache.Adapter in Plausible.Cache
Marking the test as not slow anymore
* Use Cache Adapter when tracking sessions
* Use Cache Adapter for UA parsing
* Rename child identifiers - cachex is obsolete now
* Test stats tracking
* Update grafana metrics
* Put all caches under common child specification
* Try less
* Shorten the function delegation path
* Remove `add_percentage`, calculate percentages in clickhouse queries
This simplifies querying logic and avoids doing extra queries and avoids
race conditions.
* Remove special none handling from breakdowns, handling percentages correctly
* Add (failing) test showing expected add_percentage behavior for user making multiple sessions
* Update add_percentage behavior to use separate subqueries
* Refactor: Explicitly add field names to INSERT
This avoids issues when code schema is out of sync with real schema
* Dont write session parameters to events
These would only be stored on first event anyways. Work remains to be done
on tests which have their own helper
* Remove writes to country_code in a test
* Remove old columns from being accessible in elixir code
* Update most tests to use new way of adding session props to events
* Update testing harness
* Update stats controller test
* Update for shield rules
* update breakdown tests
* Fix typing of state for dialyzer
* Drop support for old session attributes code
* Update remaining tests
* cond -> if
* Create a stub of site settings section for imports and exports
* Use legacy site import indication to determine UA import handling
* Add provisional logos for upcoming import sources
* Stub basics of import page
* Add very rudimentary support for multiple UA imports
* Implement imports list as live view
* Add support for opening LV modal from backend and closing from frontend
* Introduce notion of themes to `button` and `button_link` components
* Add confirmation modal on deleting import
* Swap GA4 logo
* Implement disabled state support for `button_link` component
* Disable export and non-implemented import sources
* Use native starts start date for upper boundary of import time range
* Ensure integrations view uses legacy UA import flow
* Remove unnecessary preload in SiteController
* Remove unnecessary exception for legacy imports
* Move API controller stats tests under PlausibleWeb
* Test listing imports
* Add test for explicit listener setup
* Add tests for legacy flag state in UA importer
* Add test for purging legacy import data
* Add tests for `Sites.native_stats_start_date`
* Test forgetting imports
* Add `Stats.Clickhouse.imported_pageview_counts/1` and fix test flakiness
* Show page view counts on imports list
* Add tests for static imports and exports view
* Adjust button look slightly
* Use `case` instead of `cond`
* Make feature flag customisable per site
* Fix buttons and empty state styling
* Add another import to seeds
* Use JS confirm dialog instead of modal for deletion confirmations
* Revert "Add support for opening LV modal from backend and closing from frontend"
This reverts commit 260e6c753032b451542e24be9edc2118790b5a00.
* Default `legacy` to false when inserting new import jobs
* Drop `method` attribute from `button_link` and `unstyled_link` components
* add csv importer
* make table validation explicit
* update some docs
* improve docs
* add minio container to ci
* more tests
* eh
* continue
* add passing test
* add failing test
* add config test
* add minio to Makefile
* testcontainers
* remove extra whitespace
* explain the implementation a bit
* account for async deletes in tests
* bounces is UInt32
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
---------
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
* Migration: add country rules
* Add CountryRule schema
* Implement CountryRule cache
* Add country rules context interface
* Start country rules cache
* Lookup country rules on ingestion
* Remove :shields feature flag from test helpers
* Add nested sidebar menu for Shields
* Fix typo
* IP Rules: hide description on mobile view
* Prepare SiteController to handle multiple shield types
* Seed some country shield
* Implement LV for country rules
* Remove "YOU" indicator from country rules
* Fix small build
* Format
* Update typespecs
* Make docs link point at /countries
* Fix flash on top of modal for Safari
* Build the rule struct with site_id provided up-front
* Clarify why we're messaging the ComboBox component
* Re-open combobox suggestions after pressing Escape
* Update changelog
* Fix font size in country table cells
* Pass `added_by` via rule add options
* Display site's timezone timestamps in rule tooltips
* Display formatted timestamps in site's timezone
And simplify+test Timezone module; an input timestamp converted
to UTC can never be ambiguous.
* Remove no-op atom
* Display the maximum number of rules when reached
* Improve readability of remove button tests
* Credo
---------
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
* improve test
* add os to os_version breakdown
...and add operating_system_versions.csv to the CSV export
* fix conversion rate for os_version breakdown
* update changelog
* fix existing CSV tests
* use case instead of cond
* Add `GET /capabilities` to Plugins API
It aims to:
- help the client verify the data-domain the token is associated with
- list all the features available for the site's owner
(and therefore determine availability of the subset of those for the current
Plugins API caller)
The endpoint does not require authentication, in the sense that it'll
always respond with 200 OK. However when the token is provided,
a verification lookup is made.
* Remove IO.inspect() call
* Credo
* Aesthetics
* s/send_resp/send_error/
* Call preload just once
This will makes it impossible to store session attributes on events.
Looking at production data also revealed no cases where these updates
are effective.
* Allow e-mail exclusion in team members quota
* Exclude invitee from quota on invitation create
* Enable invitation submission but report errors on quota violation
* Use a single interface for team members quota
* Check the `Keyword.validate/2` result
* Update test/plausible_web/controllers/site/membership_controller_test.exs
Co-authored-by: Uku Taht <Uku.taht@gmail.com>
---------
Co-authored-by: Uku Taht <Uku.taht@gmail.com>
* Revert "Unify percentage change for CR and bounce_rate (#3781)"
This reverts commit a6b1a6ebc7.
* Revert "Bring Stats API up to speed: Add `conversion_rate` to Aggregate and Breakdown (#3739)"
This reverts commit 672d682e95.
* Fix conversion rate change calculation
The change in conversion rate should be calculated similar to bounce rate.
For example, an increase of 25% -> 50% should not be a 100% change, but
a 25% change instead.
* Use the same comparison function in Stats API and dashboard API
This commit fixes a bug where the percentage change reported by the Stats
API is different from the one returned by the internal dashboard API.
* changelog update
* WIP
* Allow `experimetnal_session_count` request serialization
* Extend `Plausible.Stats.Query` with `experimental_session_count` flag
* Add `FunWithFlags` actor implementation for `Site`
* Change the way sessions are retrieved
* Remove redundant test
* Format
* Update the test
---------
Co-authored-by: Uku Taht <uku.taht@gmail.com>
* disable event metric with include_imported in every case
* add missing test for metric validation
* refactor metric validation functions
* implement conversion_rate metric validation
* move calculate_cr function into Stats.Util
* Refactor: Move aggregate CR logic into Stats.aggregate
* define atoms to exist
* Ensure that CR does not depend on visitors being queried
If 'visitors' are already queried, we'll use that value. Otherwise we'll
need to make another query to fetch it.
* confirm Stats API aggregate supports CR (tests only)
* small refactor
This is the only 'event_property' left after pattern matching on all
others in the function clauses defined above.
* Make it possible to optionally query conversion_rate
...in breakdown queries (excluding goal and custom prop breakdown)
* A little refactor asking for revenue metrics
1. The `@revenue_metrics` module attribute is an empty list on full build
anyway
2. We don't need to query for revenue metrics if there are no revenue goals
returned in the given query (even if revenue goals exist in site.goals)
3. Revenue metrics are already dropped in prop breakdown without a goal
filter via (get_revenue_tracking_currency/3)
* Make it possible to optionally query conversion_rate (continuation)
... also from a custom prop and goal breakdown
* Frontend adjustments to the Locations report
* Display conversion rate in Regions and Cities (ListReport view)
* Display total conversions, conversions (visitors), and CR in the
"Details" modals of Countries, Regions, and Cities
* Move the percentage into a separate column in the Countries details table
* confirm Stats API breakdown supports conversion_rate (tests only)
* small refactor: extract maybe_add_time_on_page function
* Make it possible to query cr alone
... (without the visitors metric). Already supported in aggregate, this
commit only implements it for the breakdown API.
* Reuse Stats.Util helper functions from b02db88 for aggregate API
We can follow the same logic as with breakdown for manually adding
`visitors` into the metrics list and taking it out of the response
later on.
That way we don't have to make another query, e.g. in a case where
only pageviews and conversion rate is queried. Also keeps things
consistent.
* changelog update
* fix test after resolving merge conflict
* Use explicit string->atom mapping instead of casting
* alias Util module instead of importing it
* use Enum.empty instead of Enum.any
* improve readability
* rename special_metrics to computed_metrics and explain with a comment
* rename visitors_without_event_filters to total_visitors
* keep a single function for removing unwanted metrics
---------
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
* Clean up references to no longer active `google_analytics_imports` Oban queue
* Stub CSV importer
* Add SiteImport schema
* Rename `Plausible.Imported` module file to match module name
* Add `import_id` column to `Imported.*` CH schemas
* Implement Importer behavior and manage imports state using new entities
* Implement importer callbacks and maintain site.imported_data for UA
* Keep imports in sync when forgetting all imports
* Scope imported data queries to completed import IDs
* Mark newly imported data with respective import ID
* Clean up Importer implementation a bit
* Test querying legacy and new imported data
* Send Oban notifications on import worker failure too
* Fix checking for forgettable imports and remove redundant function
* Fix UA integration test
* Change site import source to atom enum and add source label
* Add typespecs and reduce repetition in `Plausible.Imported`
* Improve documentation and typespecs
* Add test for purging particular import
* Switch email notification templates depending on import source
* Document running import synchronously
* Fix UA importer args parsing and ensure it's covered by tests
* Clear `site.stats_start_date` on complete import to force recalculation
* Test Oban notifications (h/t @ruslandoga)
* Purge stats on import failure right away to reduce a chance of leaving debris behind
* Fix typos
Co-authored-by: hq1 <hq@mtod.org>
* Fix another typo
* Refactor fetching earliest import and earliest stats start date
* Use `Date.after?` instead of `Timex.after?`
* Cache import data in site virtual fields and limit queried imports to 5
* Ensure always current `stats_start_date` is used
* Work around broken typespec in Timex
* Make `SiteController.forget_imported` action idempotent
* Discard irrecoverably failed import tasks
* Use macros for site import statuses
There's also a fix ensuring only complete imports are considered
where relevant - couldn't isolate it as it was in a common hunk
* Use `import_id` as worker job uniqueness criterion
* Do not load imported stats data in plugins API context
---------
Co-authored-by: hq1 <hq@mtod.org>
* ORDER BY referrer_source for spikes job
This is more consistent with the rest of the queries
* Refactor top_sources -> top_sources_for_spike
* Remove more dead code
* Remove unused arguments
* Remove unused select arguments
* Add a test to top_sources_for_spike
* Add Ecto.Network dependency
* Migration: Add ip block list table
* If Cachex errors out, mark the cache as not ready
* Add IPRule schema
* Seed IPRules
* Add Shields context module
* Implement IPRuleCache
* Start IPRuleCache
* Drop blocklisted IPs on ingestion
* Cosmetic rename
* Add settings sidebar item
* Consider IPRuleCache readiness on health checks
* Fix typo
* Implement IP blocklist live view
* Update moduledocs
* Extend contextual module tests
* Convert IPRules LiveView into LiveComponent
* Keep live flashes on the tabs view
* Update changelog
* Format
* Credo
* Remove garbage
* Update drop reason typespecs
* Update typespecs for cache keys
* Keep track of who added a rule and when
* Test if adding via LV prefills the updated_by tooltip
* Update ecto_network dependency
* s/updated_by/added_by
* s/drop_blocklist_ip/drop_shield_rule_ip
* Add docs link
* s/Updated/Added
* WIP: PropFilterRow
* Get multi-behavior working
* Render multiple prop filters in one
* Modal reads from query string correctly
* Backend support for multiple custom property filters
* Add backend tests for multiple custom property filters
* Disable already selected options in property keys
We can't allow choosing the same property multiple times without changing the request
params, which we decided against
* Allow choosing any property under Behaviors > Custom props even if custom prop filter applied
This was a limitation (I believe) introduced by using ARRAY JOINs to query custom properties
* CHANGELOG.md
* Solve credo warning about too deep nesting
* Update assets/js/dashboard/stats/modals/prop-filter-modal.js
Co-authored-by: RobertJoonas <56999674+RobertJoonas@users.noreply.github.com>
* Refactor internal function for clarity
* Add another step -> Add another
* Solve 500 error
* Separate boxes per property filter
* Retain other filters in props table
* removeFilter behavior for props
* matches_member support for custom props
* filter_suggestions for prop keys should account for prop filter
* find over filter
* refactor appliedFilters
* FILTER_TYPES => FILTER_OPERATIONS
* Make add another link not wrap the whole page
* Unique keys
---------
Co-authored-by: RobertJoonas <56999674+RobertJoonas@users.noreply.github.com>
* Reorganize how subscriptions/trials are evaluated
* Bugfix: expired trial+no subscriptions should not have access to extra features
* Make self-hosted users always on trial
* Seed secondary user with password
* Format
* Fix docs
* Fix small_test run
* Run the test only on full_build
* More tweaks to small builds
* Allow [Goals] for expired trials with no subscription
* Simplify caches config
The intervals were proven to never change really,
and previous shape made them not very discoverable either.
We'll look into a more declarative setup.
* Aim for more declarative supervision tree setup
* Generalize `Plausible.Cache`
This makes the `Site.Cache` module implement the specifics,
leaving the common bits reusable for upcoming cache processes.
* Generalize `Plausible.Cache` warmers
* Fix typos
* Revert "Remove 0-sized queue"
This reverts commit 6d229b3f70.
* Revert "Temporarily remove notification cron worker (#3732)"
This reverts commit 447e3929cb.
* Revert "Temporarily disable accept_traffic_until actions (#3730)"
This reverts commit 58afe3376f.
* Send accept_traffic_until notifications at 8 UTC rather than 5
* Add option for dry-run
* Expose dry_run in a dedicated function
* add tests for filtering by goal in timeseries and aggregate
* refactor filter parsing
* stop returning custom props in event:goal breakdown
* test breaking down wildcard pageview goals
* extract filter utils
* parse more goal filter options
* add passing tests for new filter types
* do not allow querying session metrics with a goal filter
* remove unused page_match property
* test that non-configured goals are not returned in breakdown
* enforce filtered goals configured
* update changelog
* Allow simple filtering by revenue goals
This does not mean that revenue metrics are supported. If a revenue goal
is filtered by, we treat it like a simple custom event goal in the API.
* use List.wrap
* Make subsequent query boundaries idempotent
This should prevent time-sensitive race conditions
on subsequent `Plausible.Stats.*` calls for the same query.
Not sure if there are more places where now() is
dynamic relative to query life cycle, but it's a start.
* Format
* Update lib/plausible/stats/query.ex
Co-authored-by: Wojtek Mach <wojtekmach@users.noreply.github.com>
* Match on `Query.now` in a test
---------
Co-authored-by: Wojtek Mach <wojtekmach@users.noreply.github.com>
* Move imported tables schemas to separate modules outside Google ns
* Move buffer for imports to Imported ns
* fix schema newlines
* Extract UA import processing and persistence
* Decouple analytics worker implementation from UA
* Rename env variable for import buffer size
* Preserve old import queue until release
* Allow `matches` operator to work in BE for custom props
Note: No FE support yet, needs further testing
* feat: allow choosing `contains` for property filters in the UI
* no autocomplete on prop values if `contains` for consistency
* CHANGELOG.md
* Fix: Handle (none) property in property breakdowns when using matching
When matching we should always exclude (none)
* Remove allowance_required field from grace_period
Since we are now preventing customers from subscribing to a plan that
does not accommodate their pageview usage, there is no need for an extra
check on removing the grace period after a successful upgrade.
This extra check is the reason why the automatic unlocks have recently
failed in several cases.
* refactor outgrown subscription notices
* make a test actually test the described functionality
* Apply greater pageview allowance margin only for trial upgrades
...in order to prevent cancelled or paused subscriptions from subscribing
to plans that would still leave their account locked.
* Mark the entire ChoosePlanTest module full build only
* remove account locking guide
This is irrelevant for self-hosters, and the internal knowledge base is
a better place for this document. Moved it there.
* refactor Keyword get clause
* add a pattern matching assertion in code
* Fix a bug
This commit fixes a bug where the timeseries weekly interval query for a
month returned 0 visitors for the first week.
This happened because the start of the month defining the first week was
missing the UTC -> site.timezone conversion.
* Update test/plausible_web/controllers/api/stats_controller/main_graph_test.exs
Remove dot from test description
Co-authored-by: Karl-Aksel Puulmann <macobo@users.noreply.github.com>
---------
Co-authored-by: Karl-Aksel Puulmann <macobo@users.noreply.github.com>
* Make modal for goal settings trigger without BE roundtrip
* Turn goal form into a live component and extract modal into a wrapper
* Further extract modal component and handle reset action
* Make ComboBox selection callback more flexible
* Add rudimentary loading state to dialog
* Make form unaware of being put inside a modal
* Make modal a live component and completely reset contents on open server-side
* Try to avoid race condition
* Fix race condition
* Remove unnecessary conditional on socket assigns
* Add typespecs and fix formatting
* Make goals form high latency friendly
* Fix tests to account for goal settings form becoming live component
* Fix goal settings form live component declaration
* Add documentation for modal
* Fix small build test
* Fix typo
Co-authored-by: hq1 <hq@mtod.org>
* Revert no longer necessary test changes from 46f65d9
* Fix and clean up modal styling
* Keep focus on dialog when open and show only spinner on backdrop when loading
* Adjust corners and shadows and implement open/close transitions
* Lock body scroll when modal is open
* Make modal top-aligned again to avoid jumping around on variable content height
---------
Co-authored-by: hq1 <hq@mtod.org>
* Reapply "Sentry context in live views (#3672)"
This reverts commit 5449fead160064b8a0081c458cc5dcd34399eb0b.
* Make sure `:selection_made` is handled in `GoalSettings.Form`
That was a bit unepexcted.. normally `handle_info` is injected
by the LiveView use macro and it discards any message gracefully.
After switching to `use PlausibleWeb, :live_view` we're also
using `PlausibleWeb.Live.Flash` that happens to inject its own receive
clause for closing the flash. Which then renders the original,
overridable, `handle_info` catch-all obsolete.
* Update LV SentryContext only on connected sockets
(first mount already has the right context coming from Sentry plug)
* Make sure Live.ChoosePlan passes `current_user_id` session key
* Add common LiveView macro to PlausibleWeb
* Keep peer data, URI and UA in /live websocket metadata
* Use new PlausibleWeb macro in existing LiveViews
* Implement adding some basic Sentry context `on_mount`
* Format
* Use macro in Live.FunnelSettings
* Update FunnelSettings.Form
* Fall back to UTC when timezone gap found
* bugfix 1
* bugfix 2
* Apply safe tz conversion to all cases where it's done on a ts other than now
---------
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
* Display premium features tabs on the dashboard
This commit makes the funnels and props tab on the dashboard visible
even when the site owner's plan does not have access to that feature.
This is to raise awareness of those features, and if the site owner does
not want to see that tab, they can still click "Hide this report" to
hide it.
Previously, when the plan did not support a feature, the feature module
`enabled/1` function returned `false`, regardless of the
`sites.feature_enabled` toggle. This commit creates a new function
called `opted_out/1` to differentiate access from explicitly opting out
a feature.
* Remove unused data-conversions-enabled attribute
* DRY Plausible.Billing.Feature.check_availability/1 function
* Allow opting out features the user doesn't have access to
* add upgrade CTA to FeatureSetupNotice
* fix JS linting errors
* simplify notice.js
* fix behaviour when deleting funnels saved to localstorage
In case some other funnel exists, we will use that as the default
selected one. If not, a feature setup notice will be displayed again.
---------
Co-authored-by: RobertJoonas <56999674+RobertJoonas@users.noreply.github.com>
Co-authored-by: Robert Joonas <robertjoonas16@gmail.com>
* remove unused code
* add e.name == "pageview" condition to pageview goals
This fixes the weird behavior where filtering by a pageview goal would
also return custom events and vice versa.
* update changelog
* Update accept_traffic_until notifications:
- extend has_stats to 48h
- ensure the user is properly greeted
* Clarify the structure passed to email template function
* restore special props access for growth plans
* format
* refactor if condition
Co-authored-by: hq1 <hq@mtod.org>
* format
---------
Co-authored-by: hq1 <hq@mtod.org>
* Update communication
* Remove an unreachable function (mistyped)
* [migration] Make accept_traffic_until a date
* Fix typo
* Set `accept_traffic_until` when creating a site
* Update sites `accept_traffic_until` on subscription change
* Add a note to yearly cancellation notification
* Rephrase annual e-mail for clarity
* Pass the small build test
* Add email notifications
* Fixup
* Implement `accept_traffic_until` notification worker
* Fixup - no need to test this for small build
* Update moduledoc
* Move moduletag
* s/sent_at/sent_on
* Use WHERE NOT EXISTS instead of LEFT JOIN
* Use upsert when tracking notifications sent
* Store sent marker before actually sending notification
* Prefer to keep `accept_traffic_until` on the user record
This gives us a single source of truth, addresses cases like
ownership transparently, simplifies the code and enables CRM toggles.
The only downside is that there's another join performed in the
Sites.Cache full refresh - in this case, small refreshes are
skipped - but this is fine, since the traffic will be let in
anyway.
* Expose `accepted_traffic_until` in the CRM
* Update lib/plausible/auth/user.ex
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
* Preload owner in CRM
* Use the offset parameter in trial over e-mail contents
* Format
* Harden cache test
---------
Co-authored-by: Adrian Gruntkowski <adrian.gruntkowski@gmail.com>
* use more convenient testing functions
* do not display + sign with 0% change in emails
* Rename module/file/function names
before, `weekly_report` was also used for monthly reports and that was a
bit confusing to read in code.
* Refactor send_email_report.ex
This commit improves readability by refactoring the code into smaller
functions and reducing the number of arguments given to functions.
But more importantly, it stops making duplicate stats queries for every
email recipient by moving the queries out of the for loop.
* Refactor: move querying logic out of the worker module
and merge all stats information under a single `stats` assign.
* Move limit enforcement to accepting site ownerhsip transfer
* enforce pageview limit on ownership transfer accept
* Refactor plan limit check logic
* Extract `ensure_can_take_ownership` to `Invitations` context and refactor
* Improve styling of exceeded limits notice in invitation dialog and disable button
* styling improvements to notice
* make transfer_ownership return transfer to self error
* do not allow transferring to user without active subscription WIP
* Add missing typespec and improve existing ones
* Fix formatting
* Explicitly label direct match on function argument for clarity
* Slightly refactor `CreateInvitation.bulk_transfer_ownership_direct`
* Exclude quota enforcement tests from small build test suite
* Remove unused return type from `invite_error()` union type
* Do not block plan upgrade when there's pending ownership transfer
* Don't block and only warn about missing features on transfer
* Remove `x-init` attribute used for debugging
* Add tests for `Quota.monthly_pageview_usage/2`
* Test and improve site admin ownership transfer actions
* Extend tests for `AcceptInvitation.transfer_ownership`
* Test transfer ownership controller level accept action error cases
* Test choosing plan by user without sites but with a pending ownership transfer
* Test invitation x-data in sites LV
* Remove sitelocker trigger in invitation acceptance code and simplify logic
* Add Quota test for `user.allow_next_upgrade_override` being set
* ignore pageview limit only when subscribing to plan
* Use sandbox Paddle instance for staging
* Use sandbox paddle key for staging and dev
---------
Co-authored-by: Robert Joonas <robertjoonas16@gmail.com>
* move format_price to Plausible.Billing
* move PlausibleWeb.Components.Billing file to subfolder
* extract new Notice module
* rename test file and module name
* move growth_grandfathered notice to notice.ex
* extract a PlanBenefits module
* extract PlanBox component
* extract PageviewSlider component
* fix plan benefits text color
* Remove business tier feature flag
This commit removes all code branches related to the business tier
feature flag, as we're not flipping this flag off anymore. It also
removes unused routes, e.g. /billing/change-plan and /billing/upgrade
* remove unused billing templates
* refactor with clause to case instead
* assert on the url in email tests
---------
Co-authored-by: Robert Joonas <robertjoonas16@gmail.com>
* remove unused functionality
We can now safely delete all the logic around users who are on trial and
signed up *before* the business tiers release, since that's no longer
possible
* add monthly_pageview_limit fn clause that takes a user
* make Quota.site_limit return enterprise site limit
...not `:unlimited`, as we still need to display it
in the account settings.
* make `team_member_limit/1` return :unlimited on small_build
* improve team_member_usage/1 function doc
* stop displaying unlimited symbol in usage section
These unlimited limits include:
* `monthly_pageview_limit` for trials
* `team_member_limit` for old enterprise plans
* `site limit` for old accounts (before 2021-05-05)
* format
* small refactor case clause + move mod vars
* review suggestions