analytics/test/plausible_web/controllers/api/stats_controller/cities_test.exs
Vini Brasil 535874be6f
Reject unknown imported cities from queries (#2675)
* 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
2023-02-15 07:35:35 -03:00

51 lines
2.3 KiB
Elixir

defmodule PlausibleWeb.Api.StatsController.CitiesTest do
use PlausibleWeb.ConnCase
describe "GET /api/stats/:domain/cities" do
defp seed(%{site: site}) do
populate_stats(site, [
build(:pageview, country_code: "EE", subdivision1_code: "EE-37", city_geoname_id: 588_409),
build(:pageview, country_code: "EE", subdivision1_code: "EE-37", city_geoname_id: 588_409),
build(:pageview, country_code: "EE", subdivision1_code: "EE-37", city_geoname_id: 588_409),
build(:pageview, country_code: "EE", subdivision1_code: "EE-39", city_geoname_id: 591_632),
build(:pageview, country_code: "EE", subdivision1_code: "EE-39", city_geoname_id: 591_632)
])
end
setup [:create_user, :log_in, :create_new_site, :add_imported_data, :seed]
test "returns top cities by new visitors", %{conn: conn, site: site} do
conn = get(conn, "/api/stats/#{site.domain}/cities?period=day")
assert json_response(conn, 200) == [
%{"code" => 588_409, "country_flag" => "🇪🇪", "name" => "Tallinn", "visitors" => 3},
%{"code" => 591_632, "country_flag" => "🇪🇪", "name" => "Kärdla", "visitors" => 2}
]
end
test "when list is filtered returns one city only", %{conn: conn, site: site} do
filters = Jason.encode!(%{city: "591632"})
conn = get(conn, "/api/stats/#{site.domain}/cities?period=day&filters=#{filters}")
assert json_response(conn, 200) == [
%{"code" => 591_632, "country_flag" => "🇪🇪", "name" => "Kärdla", "visitors" => 2}
]
end
test "does not return missing cities from imported data", %{conn: conn, site: site} do
populate_stats(site, [
build(:imported_locations, country: "EE", region: "EE-37", city: 588_409),
build(:imported_locations, country: nil, region: nil, city: 0),
build(:imported_locations, country: nil, region: nil, city: nil)
])
conn = get(conn, "/api/stats/#{site.domain}/cities?period=day&with_imported=true")
assert json_response(conn, 200) == [
%{"code" => 588_409, "country_flag" => "🇪🇪", "name" => "Tallinn", "visitors" => 4},
%{"code" => 591_632, "country_flag" => "🇪🇪", "name" => "Kärdla", "visitors" => 2}
]
end
end
end