This pull request adds support for multiple comparison modes, changes the comparison checkbox to a combobox, and implements the year over year comparison mode. The feature is still behind a feature flag.
Co-authored-by: Uku Taht <uku.taht@gmail.com>
* globally rename 'pages_per_visit' to 'views_per_visit'
* change the order of top stats
* rename 'Visits' to 'Total visits' in the UI
* add views_per_visit to UI
* put the new metric under a feature flag
* add new metric to CSV export under feature flag
* mix format
* use only one feature flag
* refactor metric validation
* link to the correct docs section
* add the new metric to aggregate API
* explicitly remove __internal_visits
The overall metric selection is well defined by
`Plausible.Stats.Timeseries.empty_row/2`. The only metric that needs
to be removed from the timeseries response is __internal_visits.
This commit also moves the `remove_internal_visits_metric` function to a
new Util module to be used by both breakdown and timeseries.
* add the new metric to timeseries API
* mix format
* add moduledoc to keep credo happy
* convert pages_per_visit to string straight away
* do rounding in db query
* query # of visits with sum(sign) instead
* stop converting pages_per_visit to string
* Use user-agent instead of screen_width to get device type
Co-authored-by: eriknakata <erik.nakata5@gmail.com>
* Fix credo
* Log on unhandled UAInspector device type
* Make 'browser' the default tab in devices report
* Remove device tooltip
* Remove screen_width from ingestion completely
* Remove browserstack harness, run playwright directly
* Select meta key based on OS platform
* Run CI tests in parallel
* Improve device match readability
* Add changelog
---------
Co-authored-by: eriknakata <erik.nakata5@gmail.com>
* Clickhouse migration: add ingest_counters table
* Configure ingest counters per MIX_ENV
* Emit telemetry for ingest events with rich metadata
* Allow building Request.t() with fake now() - for testing purposes
* Use clickhousex branch where session_id is assigned to each connection
* Add helper function for getting site id via cache
* Add Ecto schema for `ingest_counters` table
* Implement metrics buffer
* Implement buffering handler for `Plausible.Ingestion.Event` telemetry
* Implement periodic metrics aggregation
* Update counters docs
* Add toStartOfMinute() to ordering key
* Reset the sync connection state in `after` clause
* Flush counters on app termination
* Use separate Repo with async settings enabled at config level
* Switch to clickhouse_settings repo root config key
* Add AsyncInsertRepo module
* Add visits metric and make it graphable
* include visits metric in csv export (visitors.csv)
* put visits under a feature flag (CSV export)
* feature flag for displaying visits on the dashboard
* fix formatting
* add visits metric to top stats (fix)
* fix imported_test to expect visits metric included
* fix formatting
* Stop relying on implicitly selected `visits` metric
* Make the `visits` metric more explicit in imported data queries
* Rename internally used `visits` to `__internal_visits`
* Use HeadlessUI for search select box
* Remove downshift from package.json
* More consistent API for Combobox component
* Combine toFilterType and valueWithoutPrefix into a single function
* Rename MyCombobox -> PlausibleCombobox
* Update webpack-cli
* Disable cache for build
* Revert "Disable cache for build"
This reverts commit aa130541f8.
* Disable cache for build
* Update webpack dependencies
* Remove glob from webpack config
* Webpack is required by package.json
* Require autoprefixer in postcss config
* Revert build changes
* Fix styling for dark mode
* Reject unknown imported cities from queries
This commit fixes a bug where the city report returned `N/A` entries.
The functions that build imported data queries were using SQL
`COALESCE`, assuming city data is `NULL` when unknown, when actually its
unknown value is `0`.
This commit addresses the problem using SQL `NULLIF` combined with the
previous `COALESCE` call. With this change both `0` and `NULL` are
treated as unknown.
Since 1cb07efe6d cities can be `NULL`, but
previously we saved `0` as unknown.
Closes#1960
* Add entry to CHANGELOG
* Ignore cyclomatic complexity Credo check
This commit adds city data to imported records from Google Analytics. The
current implementation sets city to 0 because GA does not use the GeoNames
database.
Google Analytics Reporting API uses [Geographical IDs](https://developers.google.com/analytics/devguides/collection/protocol/v1/geoid)
to identify cities and countries. Plausible uses
[GeoNames](https://geonames.org/) and I couldn't find databases corelating the
two.
Fortunately, GA also returns the city name and this commit uses the city name
and the country ISO code to find the Geoname ID. To avoid making expensive ETS
searches, I created another ETS table in the Location library that uses
{country, city} as a key.
Related PR: https://github.com/plausible/location/pull/3
* Configure ingest repo access/pool size
If I'm not mistaken 3 is a sane default, the only
inserts we're doing are:
- session buffer dump
- events buffer dump
- GA import dump
And all are serializable within their scopes?
* Add IngestRepo
* Start IngestRepo
* Use IngestRepo for inserts
* Annotate ClickhouseRepo as read_only
So no insert* functions are expanded
* Update moduledoc
* rename alias
* Fix default env var value so it can be casted
* Use IngestRepo for migrations
* Set default ingest pool size from 3 to 5
in case conns are restarting or else...
* Ensure all Repo prometheus metrics are collected
This commit adds support for comparing the actual showed period on the main graph with the previous one. This is a first pass and it's hidden under a feature flag because it's not feature complete yet as we want to support other comparison modes.
* Make Device section components aware of (not set)
So that no extra sub-filters are possible when the unset
top item is selected.
* Support '(not set)' in breakdown/filters
* Update expectations for export tests
* Add extra tests for returning/filtering by '(not set)'
* Add changelog entry
* Remove ListReport conditional render
* Prevent redundant sub-filters
* Fix filter text rendering
---------
Co-authored-by: Uku Taht <uku.taht@gmail.com>
* Changes to the site settings danger zone
The idea was to:
1. Show a transfer site ownership message to owners of the site only. This will make ownership transfer feature more discoverable. Will also help people to transfer ownership of a site rather than deleting the whole thing when that makes more sense
2. Add a note that site deletion is a delayed operation
3. Make some other tiny copy changes
What did I break? :)
* Fix markup so the long text wraps sooner
* Fix indent
---------
Co-authored-by: Adam Rutkowski <hq@mtod.org>
* Move Endpoint errors setup to common config
* Implement naive Sentry link resolver
* Implement error report e-mail
* Delete static sentry script
* Implement user feedback form on server errors
* Re-arrange pipe
* Use Sentry.Config.dsn() where applicable
* Fix typo
* Use Map.replace/3
Some changes to be more consistent with the emails we send. Also "valid" subscription rather than "active" subscription fits better for the different cases where this screen is shown
* fix subquery for sessions in base_event_query/2
As the 'sessions' table is using the CollapsingMergeTree engine, we have
to select session_id's distinctively. Otherwise we will get multiple rows
(with sign -1 and 1) as long as the background merge hasn't happened.
* update changelog
* use GROUP BY instead of SELECT DISTINCT
* remove comma
* Fingerprint DBConnection.ConnectionError in Sentry
* Check events before creating a site
* Enable sites limit screen
* Remove debugging remnant
* Fix buggy assertions
This wasn't doing what expected:
iex(1)> Repo.exists?(Plausible.Site, domain: "foo")
[debug] QUERY OK source="sites" db=0.6ms idle=1906.2ms
SELECT TRUE FROM "sites" AS s0 LIMIT 1 []
* Encapsulate check to satisfy credo
* Use less technically involved error message
* Bring back e-mail to the limit error message
This commit stops logging `{:invalid_address, "ip"}` errors. This
reduces noise on Sentry, that is capturing error logs. Other errors are
still logged.
This PR replaces geolix with locus to simplify self-hosted setup. locus can auto-update maxmind dbs which are recommended for self-hosters if they want city-level geolocation. locus is also a bit faster.
This PR also uses a test mmdb file from https://github.com/maxmind/MaxMind-DB for e2e geolocation tests without stubs.
* extract blinkingDot function
* position pulsating-circle with tailwind instead
* remove unused function
* extract renderStatName function
* display seconds since last realtime update
Adds a 'Last updated X seconds ago' label to the Current Visitors tooltip.
* small refactor: avoid duplication of this.props and this.state
* show the 'last updated ...' tooltip in historical
* changelog update
* use className utility function
* Filter DBConnection logs for clickhouse in Sentry
Removing the never matching clause btw
* Exclude Plug.CSRFProtection.InvalidCSRFTokenError from Sentry
* Turn common Sentry captures into logged warnings
* Exclude fonts from static conf and InvalidPathError from Sentry
* Consolidate task timeouts, incrase to 15s
* Use Task.async_stream for parallel Clickhouse queries
* Propagate Opentelemetry context to child Task process
* Fix breakdown API pagination when using event metrics
This commit fixes a bug where the subsequent breakdown API pages had
the same items as the first page. The fix sorts the underlying
ClickHouse query by timestamp, keeping the same order between requests,
as we use OFFSET/LIMIT pagination.
* Fix repeated results assertion
* Add different ORDER BY to each breakdown property
* Ignore XX and T1 countries
* Add fallback if country_code=nil
* Lookup city overrides directly in CityOverrides module
* Changelog
* Add empty moduledoc
* Remove redundant comment
* Return empty list when breaking down by event:page without events
This commit fixes a bug with pagination where breaking down by event:page
would always return results despite pagination.
Closes#2255
* Update CHANGELOG.md
* Remove show_noref behaviour
Removes query param show_noref which was used from React to control
whether to show Direct / None traffic or not. The show_noref behaviour
was untested previously.
Closes#2523
* Add changelog entry
* Fix tests
* Removed files I did not mean to check in :)
### Changes
Hello friends, I'm trying to self-host plausible on my server and have
observed that if I add a file named (for example) `secrets/LISTEN_IP` to
configure the bind IP I'll get the following error:
```
Compiling 1 file (.ex)
** (RuntimeError) Invalid LISTEN_IP '172.19.130.83
' error: :einval
/home/serafeim/plausible/config/runtime.exs:20: (file)
```
(notice that I get the same error when configuring the DATABASE_URL or
whatever comes first)
It seems that for whatever reason the File.read! will insert a newline
at the end of the file. Notice that I have double checked the file with
vim and *it does not contain a newline at the end* or at least I don't
know *how* to make the file not have a newline at the end.
Thus I'm adding a `String.trim()` there to fix that thing; even if I am
doing something wrong and my files *do* contain a newline at the end,
adding a `String.trim()` there definite won't hurt :)
Below you'll find a checklist. For each item on the list, check one
option and delete the other.
### Tests
- [ ] Automated tests have been added
- [x] This PR does not require tests
### Changelog
- [ ] Entry has been added to changelog
- [x] This PR does not make a user-facing change
### Documentation
- [ ] [Docs](https://github.com/plausible/docs) have been updated
- [x] This change does not need a documentation update
### Dark mode
- [ ] The UI has been tested both in dark and light mode
- [x] This PR does not change the UI
### Changes
This PR:
- pushes PromEx to the bottom of supervision stack to avoid Endpoint
instrumentation failure
- ensures the site cache is ready by exposing it through the health
check endpoint
- fixes event timestamps being calculated at compile time, with
regression unit and integration tests
### Tests
- [x] Automated tests have been added
- [ ] This PR does not require tests
### Changelog
- [ ] Entry has been added to changelog
- [x] This PR does not make a user-facing change
### Documentation
- [ ] [Docs](https://github.com/plausible/docs) have been updated
- [x] This change does not need a documentation update
### Dark mode
- [ ] The UI has been tested both in dark and light mode
- [x] This PR does not change the UI
* Update Sites.Cache
So it's now capable of refreshing most recent sites.
Refreshing a single site is no longer wanted.
* Introduce Warmer.RecentlyUpdated
This is Sites Cache warmer that runs only for
most recently updated sites every 30s.
* Validate Request creation early
* Rename RateLimiter to GateKeeper and introduce detailed policies
* Update events API tests - a provisioned site is now required
* Update events ingestion tests
* Make limits visible in CRM Sites index
* Hard-deprecate DOMAIN_BLACKLIST
* Remove unnecessary clause
* Fix typo
* Explicitly delegate Warmer.All
* GateKeeper.allwoance => GateKeeper.check
* Instrument Sites.Cache measurments
* Update send_pageview task to output response headers
* Instrument ingestion pipeline
* Credo
* Make event telemetry test a sync case
* Simplify Request.uri/hostname handling
* Use embedded schema, apply action and rely on get_field
* Parse event URL in Plausible.Ingestion.Request
* Parse event domain in Plausible.Ingestion.Request
* Rework ingestion pipeline processing (#2462)
* Rework ingestion pipeline processing
So that Request can have multiple domains and
based on that each event is processed uniformly.
The build_and_buffer/1 function now returns an
accumulator with all the dropped/buffered events
for further inspection.
* Reduce function complexity
* Don't chain struct fields to check for an empty host
* Separate referrer and utm tags
* Fix up `with` clause, credo was right cc @vinibrsl
Co-authored-by: Adam Rutkowski <hq@mtod.org>
Adds a new script extension that allows tracking interactions with specific HTML elements on a website. For example - to track link clicks on one specific `<a>` element, you can tag it like this:
```html
<a href=... class="plausible-event-name=<your_event_name>">
```
And you can also tag the link with custom property names and values:
```html
<a href=... class="plausible-event-name=<your_event_name> plausible-event-<your_custom_prop>=<your_value>">
```
Tagging a link as above will send a custom event with the given name and props, if a `click` or `auxclick` browser event happens, and targets the link element.
The tracking behavior is somewhat different based on the HTML element type:
- `<a>`
- triggers on `click` and `auxclick` events
- intercepts navigation based on the same rules as `outbound-links` and `file-downloads`
- `<form>`
- triggers on `submit` event
- always intercepts navigation (calls `form.submit()` after preventing default and sending the Plausible event)
- other (`<img>`, `<button>`, `<span>`, `<div>`, `<h2>`, etc ...)
- triggers on `click` and `auxclick` events
- does not prevent default to intercept possible navigation. Simply calls Plausible with the event name and props read from the element class list.
* Allow refreshing a single site cache + clear cache on prefill
* Reorganize Site.Cache tests with describe blocks
* Tidy up Cache tests
* Make sure the cache is cleared on (p)re-fill
* Allow process name customization in Cache.Warmer
* s/Cache.prefill/Cache.refresh
* Unify Cache refresh instrumentation
* Apply credo suggestion: change `with` to `case`
* Update typespecs to pass dialyzer
* Implement sites by domain caching interface + warmer
* Add test
* Implement hit rate interface
* Add moduledocs
* Fix up typespec
* s/warmer/warmer_fn
* Extract measure_duration/2
* Fix up typespec
* Log errors and return nil on cache internal errors
* Fix up non-existing cache test
* Retrieve specific db columns when pre-filling the cache
* Reduce the subset of fields retrieved from the DB
See 63f3c6233d (r89871536)
* Move schemas to paths corresponding to their namespace
* Include rate-limiting site schema fields
* Expose CRM RW access to site rate-limiting fields
* Remove 👾
* Add basic moduledoc placeholders
This commit adds OTEL tracing to external HTTP requests made with
the HttpClient module. It records the elapsed time, host, path, and
response status code.
* Implement FF-driven DB lookup for sites during ingestion
We like to see the impact of doing a simple postgres lookup on each
ingestion event. The percentage-based feature flag `:ingestion_pg_lookup`
must be set in order for lookups to be executed.
* Fix resolving Cachex stats metrics
* Enable PromEx on dev env
This commit removes the current 1% sampling on ingestion to completely
ignore ingestion traces. We are not getting enough value from those, and
we'll keep dashboard, API and background jobs traces only.
Someone mentioned there's no way to cancel from the link we include in this email (https://plausible.io/billing/upgrade) so I'm changing it to the settings page instead https://plausible.io/settings. My own https://plausible.io/billing/upgrade is a bit different than normal subscribers see it so I don't actually know if there's a way to cancel on it. If there is a way there too, feel free to ignore this
People are likely to enter (copy/paste) goals from external sources
which can lead to whitespace characters appended by accident.
That renders the goal unusable and hard to distinct visually.
Normally to fix up existing goals we would use a data migration,
but this should be good enough to check if the problem
with never appearing goals resurfaces.
This commit fixes a bug where Google Analytics import tokens were not
being refreshed properly because the function was not returning the
expected tuple. Thanks to @aerosol we can nicely test this now.
This commit fixes a bug where users clearing one import and trying to
re-import would get invalid import date ranges. This was caused because
the stats_start_date field was not updated to nil after clearing
imported stats, as this field defines the end date of the import.
* Make TestUtils module available in all tests
* Add macros patching the application env in tests
Unfortunately a lot of existing functionality relies on
certain application env setup. This isn't ideal because
the app config is a shared state that prevents us from
running the tests in parallel.
Those macros encapsulate setting up new env for test purposes
and make sure the changes are reverted when the test finishes.
* Allow passing request opts to HTTPClient.post/4
We need this to swap custom request building in
Google Analytics import.
* Unify errors when listing sites
* React: propagate backend error messages if available
* React: catch API errors in Search Terms component
* Propagate google API errors on referrer drilldown
* Handle verified properties errors in SC settings
* Add missing tests for SC settings controller
* Unify errors for fetching search analytics queries (list stats)
* Unify errors refreshing Google Auth Token
* Test fetch_stats/3 errors and replace Double with Mox
* Fixup makrup
* s/class/className
* Simplify Search Terms display in case of errors
* Fix warnings
This commit parses failed GA responses to JSON before reporting to
Sentry. This makes Sentry's PII filtering smarter, redacting only
specific keys from the response, instead of the whole string.
This pull request improves the current OpenTelemetry implementation. Currently only 1% of the spans are sent, due to the high volume of ingestion requests to /api/event. I enabled the 1% sampling to /api/event only, recording 100% of the other traces.
The Google Analytics report request may take some time, especially with big
imports with thousands of pages. To mitigate the issue this commit increases
the timeout to 60s and lowers the page size to 7,500 records per request.
This commit adds an option to override `http://localhost:8000` in
`mix send_event`. This is useful when running the server in another port
or with remote servers such as staging.
* Move clear stats functions to Plausible.Purge
* Delete both native and imported stats when deleting a site
This commit moves the delete site function to the Plausible.Purge
module, and fixes a bug where deleted sites could leave dangling
imported stats.
* Clear sites.stats_start_date after clearing stats
This commit fixes a bug where resetting stats left an invalid state of
the stats_start_date field, used for GA imports, for example.
* Refactor Plausible.Sites.stats_start_date/1 function
This commit adds documentation, typespecs and better pattern matching to
the Plausible.Sites.stats_start_date/1 function.
* Use memoized stats_start_date instead of querying CH
* Prevent domain from being updated from CRM
* Add stats_start_date to CRM site form
This commit adds stats_start_date to CRM site form, and creates a
separate Ecto changeset for CRM changes.
* Alias Plausible.Site calls
Co-authored-by: Adam Rutkowski <hq@mtod.org>
* List all timezones in CRM form
* Require sites.public in CRM changeset
Co-authored-by: Adam Rutkowski <hq@mtod.org>
* Create API to check for an active subscription
* Redirect after upgrading only when subscription is created
* Change upgrade page copy
* Add timeout notice to upgrade success page
* Overrides content-type for SVG favicons
* Organize favicon rendering
Make sure the placeholder icon is always requested from
/favicon/sources/placeholder
* Run prettier on site-switcher.js
* Yak Shave: upgrade Heroicons to 2.0
* Use HeroIcons instead of custom svg
* Update lib/plausible_web/plugs/favicon.ex
Co-authored-by: Adam Rutkowski <hq@mtod.org>
Co-authored-by: Adam Rutkowski <hq@mtod.org>
* Accept letters from non-Latin alphabets in domain names
* Replace static URLs with Router functions in settings_visibility
* Beautify dashboard URL in visibility tab
* Add IDN support to CHANGELOG
This commit increases the receive_timeout from 15s to 30s for Google
Analytics import requests. Timeouts have been reported, and I could
replay some requests that took 15-20 seconds to complete when fetching
10,000 records in a single request.
* add separate module for filter parsing
* add tests for filter parser
* allow escaping pipe character in filter value
* add documentation and doctests
* do not remove escape chars from wildcard values
* changelog update
* change the parse_filters/1 function argument
This commit fixes an exception when calling `Timex.Timezone.get/2` after
there has been a timezone change. Similar issues have already been reported
in Timex (bitwaker/timex#691, bitwalker/timex#555, bitwalker/timex#625).
This skips timezones from the list when they fail to fetch, and use
`Timex.Timezone.get/2` to get the current offset using `DateTime.utc_now/0`
instead of the `NaiveDateTime` default.
* Return error tuple instead of exception when GA request fails
* Report Google Analytics failed request body to Sentry
* Improve Google Analytics function @doc
* fixup! Report Google Analytics failed request body to Sentry
* fixup! Improve Google Analytics function @doc
* Render 404 when shared link cannot be found
* Add documentation for StatsController and shared link rendering
* Refactor shared_link/2 for more clarity
* Add changelog entry
* Use mermaid graph for sequence diagram
* Use more accurate return value in sequence diagram
* Refactor Ecto query to be more idiomatic
* Remove order dependence in test
* Restore backwards compatibility for older shared links
* Add changelog entry
* Make sure admin can grant the admin role
* Use `site` and `current_user_role` from conn.assigns to avoid extra lookups
* Add some missing documentation
* Restrict owners in the `update_role` action
* Move @moduledoc to appropriate location
* Use Ecto.Enum to get role atoms
* Remove unused functionality
* Ensure that owners cannot lock themselves out
* Add question mark to `can_grant_role`
Co-authored-by: Adam Rutkowski <hq@mtod.org>
* Use strict short-circuit operator for booleans
Co-authored-by: Adam Rutkowski <hq@mtod.org>
Co-authored-by: Adam Rutkowski <hq@mtod.org>
This commit fixes a bug where the timezone list was sorted by the
standard offset, not considering timezone changes. The list was working
properly, but sorting was wrong.
* Update Timex version from 3.7.7 to 3.7.8
* Generate timezone list from Tzdata
This commit fixes a bug where timezone changes weren't updating the
timezone list displayed when editing or creating a site.
Timezones were being pulled from a static list. This commit changes it
to generate the list from Tzdata, that uses a timezone database with
updated information on time changes. Additionally it adds more timezones
with aliases and links to the list.
Closes#1340
* Use timezone name from browser to recommend timezone
This commit matches the timezone name instead of offset to recommend a
timezone when creating a new site. The JavaScript Intl.DateTimeFormat
API is widely supported according to the link. In any case, if the
timezone fails to match by name, it fallbacks to the offset strategy.
https://caniuse.com/mdn-javascript_builtins_intl_datetimeformat_resolvedoptions_computed_timezoneCloses#904
* Fixup error reporting (ref #2181)
Fixes two problems:
- `extra` sent to Sentry is always expected to be a map
- no `String.Chars` protocol is implemented for `Finch.Error` struct
* Use explicit paths in http client tests
* Make HTTP Client tests sync
* List all Google Analytics views during import
This commit fixes a bug where different Google Analytics views with the
same name and URI were not shown. This was caused because GA views were
stored as a map, that naturally doesn't support duplicate keys.
This change updates the GA views list to display view IDs, making it
clearer to know what is being imported. The dropdown is now grouped by
website URL.
* Put Google Analytics API URLs in app env
* Add controller test to GA view list
This commit removes some Enum calls to rely on the database for
aggregating data. This improves performance when creating new sites,
especially if the user has multiple sites.
* Replace current tooltip with Popper.js
* Merge tooltip and title for top stats
* Format bounce rate and visit duration numbers in tooltip
* Add 'width=manual' mode for embed
* Add changelog entry
* Use helper function canMetricBeGraphed
This commit handles unexpected Google Analytics responses while
importing, and logs to Sentry and Logger. This will improve
observability when things go wrong with GA imports.
* Replace Ingestion.Request headers with user_agent
* Replace generic Ingestion.Request params with specific fields
* Refactor event building function into small functions
* Move Plausible.Ingestion to Plausible.Ingestion.Event
* Add option to override event fields while building
* Rename Ingestion.Request meta to props
* Replace UTM-specific fields with generic query_params
* Remove Map.from_struct/1 call from ingestion pipeline
* Remove stash options from ingestion
* Remove invalid Jason.decode argument
Co-authored-by: Robert Joonas <robertjoonas16@gmail.com>
* Add custom message to Google invalid grant error
Co-authored-by: Robert Joonas <robertjoonas16@gmail.com>
* Test invalid_grant while refreshing Google token
Co-authored-by: Robert Joonas <robertjoonas16@gmail.com>
Co-authored-by: Robert Joonas <robertjoonas16@gmail.com>
* Add Custom telemetry for Plausible.Event.WriteBuffer, Plausible.Event.WriteBuffer and Cachex
Signed-off-by: Manu S Ajith <neo@codingarena.in>
* Rename telemetry.ex to avoid confusion with Phoenix Telemetry supervisor
Signed-off-by: Manu S Ajith <neo@codingarena.in>
* Remove duplicate event
Signed-off-by: Manu S Ajith <neo@codingarena.in>
Signed-off-by: Manu S Ajith <neo@codingarena.in>
This commit fixes a bug where fetching Google Search Console keywords
raised a FunctionClauseError. This was introduced in #2046. This commit
also adds test coverage.
* Create separate module for GA HTTP requests
* Fetch GA data entirely instead of monthly
* Add buffering to GA imports
* Change positional args to maps when serializing from GA
* Create Google Analytics VCR tests
* Fix geolocation subdivision pattern matching
This commit fixes a bug where regions were not being saved. This was
caused because Geolix response was returning an additional
`:geolocation` map key. It also adds a test case for this.
Closes#2033
* Add geolocation database to .gitignore
This commit fixes a bug where location filters were filtering stats but
not the locations list. This was caused by a `Map.put/3` call that
overrides the user filter. This commit rollbacks 5b57143273
changes and removes the `Map.put/3` call.
Closes#1982