analytics/test/plausible/site/sites_test.exs

923 lines
29 KiB
Elixir

defmodule Plausible.SitesTest do
use Plausible.DataCase
use Plausible
use Plausible.Teams.Test
alias Plausible.Sites
describe "create a site" do
test "creates a site" do
user = new_user()
params = %{"domain" => "example.com", "timezone" => "Europe/London"}
assert {:ok, %{site: %{domain: "example.com", timezone: "Europe/London"}}} =
Sites.create(user, params)
end
test "creating a site sets `legacy_time_on_page_cutoff`" do
user = new_user()
params = %{"domain" => "example.com", "timezone" => "Europe/London"}
assert {:ok, %{site: %{legacy_time_on_page_cutoff: ~D[1970-01-01]}}} =
Sites.create(user, params)
end
@tag :ee_only
test "updates team's locked state" do
user = new_user(trial_expiry_date: Date.add(Date.utc_today(), -1), team: [locked: false])
team = new_site(owner: user).team
refute team.locked
params = %{"domain" => "example.com", "timezone" => "Europe/London"}
assert {:ok, %{site: %{domain: "example.com", timezone: "Europe/London"}}} =
Sites.create(user, params, team)
assert Repo.reload(team).locked
end
test "does not start a trial for pre-teams guest users without trial expiry date" do
user = new_user() |> subscribe_to_growth_plan()
new_site(owner: user)
three_hundred_days_from_now = Date.shift(Date.utc_today(), day: 300)
user
|> team_of()
|> Ecto.Changeset.change(
trial_expiry_date: nil,
accept_traffic_until: three_hundred_days_from_now
)
|> Plausible.Repo.update!()
params = %{"domain" => "example.com", "timezone" => "Europe/London"}
user = Plausible.Repo.reload!(user)
assert {:ok, %{site: %{domain: "example.com", timezone: "Europe/London"}}} =
Sites.create(user, params)
team = user |> team_of() |> Repo.reload!()
refute team.trial_expiry_date
assert Date.compare(team.accept_traffic_until, three_hundred_days_from_now) == :eq
end
test "fails on invalid timezone" do
user = insert(:user)
params = %{"domain" => "example.com", "timezone" => "blah"}
assert {:error, :site, %{errors: [timezone: {"is invalid", []}]}, %{}} =
Sites.create(user, params)
end
test "fails for user owning more than one team without explicit pick" do
user = new_user()
_site1 = new_site(owner: user)
site2 = new_site()
add_member(site2.team, user: user, role: :owner)
params = %{"domain" => "example.com", "timezone" => "Europe/London"}
assert {:error, _, :multiple_teams, _} = Sites.create(user, params)
end
test "fails for user not being permitted to add sites in selected team" do
user = new_user()
site = new_site()
viewer_team = site.team
add_member(viewer_team, user: user, role: :viewer)
other_site = new_site()
other_team = other_site.team
params = %{"domain" => "example.com", "timezone" => "Europe/London"}
assert {:error, _, :permission_denied, _} = Sites.create(user, params, viewer_team)
assert {:error, _, :permission_denied, _} = Sites.create(user, params, other_team)
end
test "succeeds for user being permitted to add sites in selected team" do
user = new_user()
viewer_site = new_site()
viewer_team = viewer_site.team
editor_site = new_site()
editor_team = editor_site.team
add_member(viewer_team, user: user, role: :viewer)
add_member(editor_team, user: user, role: :editor)
params = %{"domain" => "example.com", "timezone" => "Europe/London"}
assert {:ok, %{site: site}} = Sites.create(user, params, editor_team)
assert site.team_id == editor_team.id
end
end
on_ee do
describe "create a site - SSO user" do
setup [:create_user, :create_team, :create_site, :setup_sso, :provision_sso_user]
test "creates a site for SSO user in a setup team", %{user: user, team: team} do
params = %{"domain" => "example.com", "timezone" => "Europe/London"}
assert {:ok, %{site: %{domain: "example.com", timezone: "Europe/London"}}} =
Sites.create(user, params, team)
end
test "does not allow creating a site in SSO user's personal team", %{team: team} do
user = add_member(team, role: :editor)
{:ok, personal_team} = Plausible.Teams.get_or_create(user)
identity = new_identity(user.name, user.email)
{:ok, _, _, user} = Plausible.Auth.SSO.provision_user(identity)
params = %{"domain" => "example.com", "timezone" => "Europe/London"}
assert {:error, _, :permission_denied, _} = Sites.create(user, params, personal_team)
end
end
end
describe "stats_start_date" do
test "is nil if site has no stats" do
site = insert(:site)
assert Sites.stats_start_date(site) == nil
end
test "is date if site does have stats" do
site = insert(:site)
populate_stats(site, [
build(:pageview)
])
assert Sites.stats_start_date(site) == Timex.today(site.timezone)
end
test "memoizes value of start date" do
site = insert(:site)
assert site.stats_start_date == nil
populate_stats(site, [
build(:pageview)
])
assert Sites.stats_start_date(site) == Timex.today(site.timezone)
assert Repo.reload!(site).stats_start_date == Timex.today(site.timezone)
end
end
describe "native_stats_start_date" do
test "is nil if site has no stats" do
site = insert(:site)
assert Sites.native_stats_start_date(site) == nil
end
test "is date if site does have stats" do
site = insert(:site)
populate_stats(site, [
build(:pageview)
])
assert Sites.native_stats_start_date(site) == Timex.today(site.timezone)
end
test "ignores imported stats" do
site = insert(:site)
insert(:site_import, site: site)
assert Sites.native_stats_start_date(site) == nil
end
end
describe "has_stats?" do
test "is false if site has no stats" do
site = insert(:site)
refute Sites.has_stats?(site)
end
test "is true if site has stats" do
site = insert(:site)
populate_stats(site, [
build(:pageview)
])
assert Sites.has_stats?(site)
end
end
describe "get_for_user/2" do
@tag :ee_only
test "get site for super_admin" do
user1 = new_user()
user2 = new_user()
patch_env(:super_admin_user_ids, [user2.id])
%{id: site_id, domain: domain} = new_site(owner: user1)
assert %{id: ^site_id} = Plausible.Sites.get_for_user(user1, domain)
assert %{id: ^site_id} =
Plausible.Sites.get_for_user(user1, domain, [:owner])
assert is_nil(Plausible.Sites.get_for_user(user2, domain))
assert %{id: ^site_id} =
Plausible.Sites.get_for_user(user2, domain, [:super_admin])
end
end
describe "list/3 and list_with_invitations/3" do
test "returns empty when there are no sites" do
user = new_user()
_rogue_site = new_site()
assert %{
entries: [],
page_size: 24,
page_number: 1,
total_entries: 0,
total_pages: 1
} = Sites.list(user, %{})
assert %{
entries: [],
page_size: 24,
page_number: 1,
total_entries: 0,
total_pages: 1
} = Plausible.Teams.Sites.list(user, %{})
assert %{
entries: [],
page_size: 24,
page_number: 1,
total_entries: 0,
total_pages: 1
} = Sites.list_with_invitations(user, %{})
assert %{
entries: [],
page_size: 24,
page_number: 1,
total_entries: 0,
total_pages: 1
} = Plausible.Teams.Sites.list_with_invitations(user, %{})
end
test "lists guest sites, site invitations and transfers when no current team set" do
user1 = new_user()
user2 = new_user()
user3 = new_user()
user4 = new_user()
# owned site on a setup team
site1 = new_site(owner: user1, domain: "own.example.com")
Plausible.Teams.complete_setup(site1.team)
# guest site access
site2 = new_site(owner: user2, domain: "guest.example.com")
add_guest(site2, user: user1, role: :editor)
# site invitation
site3 = new_site(owner: user3, domain: "invitation.example.com")
invite_guest(site3, user1, role: :viewer, inviter: user3)
# transfer
site4 = new_site(domain: "transfer.example.com", owner: user3)
invite_transfer(site4, user1, inviter: user2)
# other team site access
site5 = new_site(domain: "team.example.com", owner: user4)
add_member(site5.team, user: user1, role: :editor)
assert %{
entries: [
%{domain: "invitation.example.com"},
%{domain: "transfer.example.com"},
%{domain: "guest.example.com"}
]
} =
Sites.list_with_invitations(user1, %{})
end
test "lists guest sites, site invitations, transfers and team sites when current team set but not setup" do
user1 = new_user()
user2 = new_user()
user3 = new_user()
user4 = new_user()
# owned site on a personal team
site1 = new_site(owner: user1, domain: "own.example.com")
# guest site access
site2 = new_site(owner: user2, domain: "guest.example.com")
add_guest(site2, user: user1, role: :editor)
# site invitation
site3 = new_site(owner: user3, domain: "invitation.example.com")
invite_guest(site3, user1, role: :viewer, inviter: user3)
# transfer
site4 = new_site(domain: "transfer.example.com", owner: user3)
invite_transfer(site4, user1, inviter: user2)
# other team site access
site5 = new_site(domain: "team.example.com", owner: user4)
add_member(site5.team, user: user1, role: :editor)
assert %{
entries: [
%{domain: "invitation.example.com"},
%{domain: "transfer.example.com"},
%{domain: "guest.example.com"},
%{domain: "own.example.com"}
]
} =
Sites.list_with_invitations(user1, %{}, team: site1.team)
end
test "lists team sites and transfers when current team set and setup" do
user1 = new_user()
user2 = new_user()
user3 = new_user()
user4 = new_user()
# owned site on a personal team
new_site(owner: user1, domain: "own.example.com")
# guest site access
site2 = new_site(owner: user2, domain: "guest.example.com")
add_guest(site2, user: user1, role: :editor)
# site invitation
site3 = new_site(owner: user3, domain: "invitation.example.com")
invite_guest(site3, user1, role: :viewer, inviter: user3)
# transfer
site4 = new_site(domain: "transfer.example.com", owner: user3)
invite_transfer(site4, user1, inviter: user2)
# other team site access
site5 = new_site(domain: "team.example.com", owner: user4)
team5 = Plausible.Teams.complete_setup(site5.team)
add_member(site5.team, user: user1, role: :admin)
assert %{
entries: [
%{domain: "transfer.example.com"},
%{domain: "team.example.com"}
]
} =
Sites.list_with_invitations(user1, %{}, team: team5)
end
test "shows both pending transfer and pinned site for user without team with guest membership" do
owner = new_user()
pending_owner = new_user()
site = new_site(owner: owner, domain: "one.example.com")
add_guest(site, user: pending_owner, role: :editor)
invite_transfer(site, pending_owner, inviter: owner)
{:ok, _} = Sites.toggle_pin(pending_owner, site)
assert %{
entries: [
%{domain: "one.example.com", entry_type: "invitation"},
%{domain: "one.example.com", entry_type: "pinned_site"}
]
} =
Sites.list_with_invitations(pending_owner, %{})
end
test "shows both pending transfer and site for user without team with guest membership" do
owner = new_user()
pending_owner = new_user()
site = new_site(owner: owner, domain: "one.example.com")
add_guest(site, user: pending_owner, role: :editor)
invite_transfer(site, pending_owner, inviter: owner)
assert %{
entries: [
%{domain: "one.example.com", entry_type: "invitation"},
%{domain: "one.example.com", entry_type: "site"}
]
} =
Sites.list_with_invitations(pending_owner, %{})
end
test "shows both pending transfer and site for user with personal team with guest membership" do
owner = new_user()
pending_owner = new_user() |> subscribe_to_growth_plan()
pending_team = team_of(pending_owner)
site = new_site(owner: owner, domain: "one.example.com")
add_guest(site, user: pending_owner, role: :editor)
invite_transfer(site, pending_owner, inviter: owner)
assert %{
entries: [
%{domain: "one.example.com", entry_type: "invitation"},
%{domain: "one.example.com", entry_type: "site"}
]
} =
Sites.list_with_invitations(pending_owner, %{}, team: pending_team)
end
test "shows only pending transfer for user with setup team with guest membership" do
owner = new_user()
pending_owner = new_user() |> subscribe_to_growth_plan()
pending_team =
pending_owner
|> team_of()
|> Plausible.Teams.complete_setup()
site = new_site(owner: owner, domain: "one.example.com")
add_guest(site, user: pending_owner, role: :editor)
invite_transfer(site, pending_owner, inviter: owner)
assert %{
entries: [
%{domain: "one.example.com", entry_type: "invitation"}
]
} =
Sites.list_with_invitations(pending_owner, %{}, team: pending_team)
end
test "does not show transfer for user with site in their personal team" do
owner = new_user()
pending_owner = new_user() |> subscribe_to_growth_plan()
pending_team = team_of(pending_owner)
site = new_site(owner: pending_owner, domain: "one.example.com")
invite_transfer(site, pending_owner, inviter: owner)
assert %{
entries: [
%{domain: "one.example.com", entry_type: "site"}
]
} =
Sites.list_with_invitations(pending_owner, %{}, team: pending_team)
end
test "does not show transfer for user with site in their setup team" do
owner = new_user()
pending_owner = new_user() |> subscribe_to_growth_plan()
pending_team = team_of(pending_owner)
site = new_site(owner: pending_owner, domain: "one.example.com")
pending_team = Plausible.Teams.complete_setup(pending_team)
invite_transfer(site, pending_owner, inviter: owner)
assert %{
entries: [
%{domain: "one.example.com", entry_type: "site"}
]
} =
Sites.list_with_invitations(pending_owner, %{}, team: pending_team)
end
test "pinned site doesn't matter with membership revoked (no active invitations)" do
user1 = new_user(email: "user1@example.com")
_user2 = new_user(email: "user2@example.com")
new_site(owner: user1, domain: "one.example.com")
site2 = new_site(domain: "two.example.com")
user1 = site2 |> add_guest(user: user1, role: :viewer)
{:ok, _} = Sites.toggle_pin(user1, site2)
revoke_membership(site2, user1)
assert %{entries: [%{domain: "one.example.com"}]} = Sites.list(user1, %{})
assert %{entries: [%{domain: "one.example.com"}]} = Sites.list_with_invitations(user1, %{})
assert %{entries: [%{domain: "one.example.com"}]} = Plausible.Teams.Sites.list(user1, %{})
assert %{entries: [%{domain: "one.example.com"}]} =
Plausible.Teams.Sites.list_with_invitations(user1, %{})
end
test "pinned site with active invitation" do
user1 = new_user(email: "user1@example.com")
user2 = new_user(email: "user2@example.com")
site1 = new_site(domain: "one.example.com", owner: user1)
site2 = new_site(domain: "two.example.com")
invite_guest(site2, user1, role: :editor, inviter: user2)
{:ok, _} = Sites.toggle_pin(user1, site1)
assert %{entries: [%{domain: "one.example.com"}]} = Sites.list(user1, %{})
assert %{
entries: [
%{domain: "two.example.com", entry_type: "invitation"},
%{domain: "one.example.com", entry_type: "pinned_site"}
]
} =
Sites.list_with_invitations(user1, %{})
assert %{entries: [%{domain: "one.example.com"}]} = Plausible.Teams.Sites.list(user1, %{})
assert %{entries: [%{domain: "two.example.com"}, %{domain: "one.example.com"}]} =
Plausible.Teams.Sites.list_with_invitations(user1, %{})
end
test "pinned site on active invitation" do
user1 = new_user(email: "user1@example.com")
user2 = new_user(email: "user2@example.com")
site1 = new_site(domain: "one.example.com", owner: user2)
add_guest(site1, user: user1, role: :editor)
{:ok, _} = Sites.toggle_pin(user1, site1)
revoke_membership(site1, user1)
invite_guest(site1, user1, role: :editor, inviter: user2)
assert %{entries: []} = Sites.list(user1, %{})
assert %{
entries: [
%{domain: "one.example.com", entry_type: "invitation"}
]
} =
Sites.list_with_invitations(user1, %{})
assert %{entries: []} = Plausible.Teams.Sites.list(user1, %{})
assert %{entries: [%{domain: "one.example.com", entry_type: "invitation"}]} =
Plausible.Teams.Sites.list_with_invitations(user1, %{})
end
test "puts invitations first, pinned sites second, sites last" do
user1 = new_user()
user2 = new_user()
user3 = new_user()
site1 = new_site(owner: user1, domain: "one.example.com")
site2 = new_site(owner: user2, domain: "two.example.com")
site3 = new_site(owner: user3, domain: "three.example.com")
site4 = new_site(domain: "four.example.com")
site5 = new_site(owner: user3, domain: "five.example.com")
invite_guest(site2, user1, role: :editor, inviter: user2)
add_guest(site3, user: user1, role: :viewer)
add_guest(site4, user: user1, role: :editor)
invite_transfer(site5, user1, inviter: user3)
{:ok, _} = Sites.toggle_pin(user1, site3)
{:ok, _pin_to_ignore} = Sites.toggle_pin(user2, site2)
site1_id = site1.id
site2_id = site2.id
site3_id = site3.id
site4_id = site4.id
site5_id = site5.id
assert %{
entries: [
%{id: ^site3_id, entry_type: "pinned_site"},
%{id: ^site4_id, entry_type: "site"},
%{id: ^site1_id, entry_type: "site"}
]
} = Sites.list(user1, %{})
assert %{
entries: [
%{id: ^site5_id, entry_type: "invitation"},
%{id: ^site2_id, entry_type: "invitation"},
%{id: ^site3_id, entry_type: "pinned_site"},
%{id: ^site4_id, entry_type: "site"},
%{id: ^site1_id, entry_type: "site"}
]
} = Sites.list_with_invitations(user1, %{})
end
test "pinned sites are ordered according to the time they were pinned at" do
user1 = new_user()
user2 = new_user()
user3 = new_user()
site1 = new_site(owner: user1, domain: "one.example.com")
site2 = new_site(owner: user2, domain: "two.example.com")
site3 = new_site(domain: "three.example.com")
site4 = new_site(domain: "four.example.com")
site5 = new_site(owner: user3, domain: "five.example.com")
invite_guest(site2, user1, role: :editor, inviter: user2)
add_guest(site3, user: user1, role: :viewer)
add_guest(site4, user: user1, role: :editor)
invite_transfer(site5, user1, inviter: user3)
{:ok, _} = Sites.toggle_pin(user1, site3)
site1_id = site1.id
site2_id = site2.id
site3_id = site3.id
site4_id = site4.id
site5_id = site5.id
Sites.set_option(user1, site1, :pinned_at, ~N[2023-10-22 12:00:00])
{:ok, _} = Sites.toggle_pin(user1, site3)
assert %{
entries: [
%{id: ^site3_id, entry_type: "pinned_site"},
%{id: ^site1_id, entry_type: "pinned_site"},
%{id: ^site4_id, entry_type: "site"}
]
} = Sites.list(user1, %{})
assert %{
entries: [
%{id: ^site5_id, entry_type: "invitation"},
%{id: ^site2_id, entry_type: "invitation"},
%{id: ^site3_id, entry_type: "pinned_site"},
%{id: ^site1_id, entry_type: "pinned_site"},
%{id: ^site4_id, entry_type: "site"}
]
} = Sites.list_with_invitations(user1, %{})
end
test "filters by domain" do
user1 = new_user()
user2 = new_user()
user3 = new_user()
site1 = new_site(owner: user1, domain: "first.example.com")
site2 = new_site(owner: user2, domain: "first-transfer.example.com")
site3 = new_site(owner: user3, domain: "first-invitation.example.com")
_site4 = new_site(owner: user1, domain: "another.example.com")
invite_guest(site3, user1, role: :viewer, inviter: user3)
invite_transfer(site2, user1, inviter: user2)
site1_id = site1.id
site2_id = site2.id
site3_id = site3.id
assert %{
entries: [
%{id: ^site1_id}
]
} = Sites.list(user1, %{}, filter_by_domain: "first")
assert %{
entries: [
%{id: ^site3_id},
%{id: ^site2_id},
%{id: ^site1_id}
]
} = Sites.list_with_invitations(user1, %{}, filter_by_domain: "first")
end
test "scopes by team when provided" do
user1 = new_user()
user2 = new_user()
user3 = new_user()
site1 = new_site(owner: user1, domain: "first.example.com")
site2 = new_site(owner: user2, domain: "first-transfer.example.com")
site3 = new_site(owner: user3, domain: "first-invitation.example.com")
site4 = new_site(domain: "zzzsitefromanotherteam.com")
invite_guest(site3, user1, role: :viewer, inviter: user3)
invite_transfer(site2, user1, inviter: user2)
team4 = Plausible.Teams.complete_setup(site4.team)
add_member(team4, user: user1, role: :admin)
assert_matches %{
entries: [
%{id: ^site1.id}
]
} = Sites.list(user1, %{})
assert_matches %{
entries: [
%{id: ^site3.id},
%{id: ^site2.id},
%{id: ^site1.id}
]
} = Sites.list_with_invitations(user1, %{})
assert_matches %{
entries: [
%{id: ^site4.id}
]
} = Sites.list(user1, %{}, team: team4)
assert_matches %{
entries: [
%{id: ^site2.id},
%{id: ^site4.id}
]
} = Sites.list_with_invitations(user1, %{}, team: team4)
end
test "handles pagination correctly" do
user1 = new_user()
user2 = new_user()
user3 = new_user()
site1 = new_site(owner: user1, domain: "one.example.com")
site2 = new_site(owner: user2, domain: "two.example.com")
site3 = new_site(domain: "three.example.com")
site4 = new_site(domain: "four.example.com")
site5 = new_site(owner: user3, domain: "five.example.com")
invite_guest(site2, user1, role: :editor, inviter: user2)
add_guest(site3, user: user1, role: :viewer)
add_guest(site4, user: user1, role: :editor)
invite_transfer(site5, user1, inviter: user3)
{:ok, _} = Sites.toggle_pin(user1, site3)
site1_id = site1.id
site2_id = site2.id
site3_id = site3.id
site4_id = site4.id
site5_id = site5.id
assert %{
entries: [%{id: ^site3_id}, %{id: ^site4_id}],
page_number: 1,
page_size: 2,
total_entries: 3,
total_pages: 2
} = Sites.list(user1, %{"page_size" => 2})
assert %{
entries: [%{id: ^site1_id}],
page_number: 2,
page_size: 2,
total_entries: 3,
total_pages: 2
} = Sites.list(user1, %{"page_size" => 2, "page" => 2})
assert %{
entries: [%{id: ^site3_id}, %{id: ^site4_id}, %{id: ^site1_id}],
page_number: 1,
page_size: 3,
total_entries: 3,
total_pages: 1
} = Sites.list(user1, %{"page_size" => 3})
# list_with_invitations
#
assert %{
entries: [%{id: ^site5_id}, %{id: ^site2_id}],
page_number: 1,
page_size: 2,
total_entries: 5,
total_pages: 3
} = Sites.list_with_invitations(user1, %{"page_size" => 2})
assert %{
entries: [%{id: ^site3_id}, %{id: ^site4_id}],
page_number: 2,
page_size: 2,
total_entries: 5,
total_pages: 3
} = Sites.list_with_invitations(user1, %{"page_size" => 2, "page" => 2})
assert %{
entries: [%{id: ^site1_id}],
page_number: 3,
page_size: 2,
total_entries: 5,
total_pages: 3
} = Sites.list_with_invitations(user1, %{"page_size" => 2, "page" => 3})
end
end
describe "set_option/4" do
test "allows setting option multiple times" do
user = new_user()
site = new_site(owner: user)
assert prefs =
%{pinned_at: %NaiveDateTime{}} =
Sites.set_option(user, site, :pinned_at, NaiveDateTime.utc_now())
prefs = Repo.reload!(prefs)
assert prefs.site_id == site.id
assert prefs.user_id == user.id
assert prefs.pinned_at
assert prefs =
%{pinned_at: nil} = Sites.set_option(user, site, :pinned_at, nil)
prefs = Repo.reload!(prefs)
assert prefs.site_id == site.id
assert prefs.user_id == user.id
refute prefs.pinned_at
assert prefs =
%{pinned_at: %NaiveDateTime{}} =
Sites.set_option(user, site, :pinned_at, NaiveDateTime.utc_now())
prefs = Repo.reload!(prefs)
assert prefs.site_id == site.id
assert prefs.user_id == user.id
assert prefs.pinned_at
end
test "raises on invalid option" do
user = new_user()
site = new_site(owner: user)
assert_raise FunctionClauseError, fn ->
Sites.set_option(user, site, :invalid, false)
end
end
test "raises on invalid site/user combination" do
user = insert(:user)
site = insert(:site)
assert_raise Ecto.NoResultsError, fn ->
Sites.set_option(user, site, :pinned_at, nil)
end
end
end
describe "toggle_pin/2" do
test "allows pinning and unpinning site" do
user = new_user()
site = new_site(owner: user)
site = %{site | pinned_at: nil}
assert {:ok, prefs} = Sites.toggle_pin(user, site)
assert prefs = %{pinned_at: %NaiveDateTime{}} = prefs
prefs = Repo.reload!(prefs)
assert prefs.site_id == site.id
assert prefs.user_id == user.id
assert prefs.pinned_at
site = %{site | pinned_at: NaiveDateTime.utc_now()}
assert {:ok, prefs} = Sites.toggle_pin(user, site)
assert %{pinned_at: nil} = prefs
prefs = Repo.reload!(prefs)
assert prefs.site_id == site.id
assert prefs.user_id == user.id
refute prefs.pinned_at
site = %{site | pinned_at: nil}
assert {:ok, prefs} = Sites.toggle_pin(user, site)
assert %{pinned_at: %NaiveDateTime{}} = prefs
prefs = Repo.reload!(prefs)
assert prefs.site_id == site.id
assert prefs.user_id == user.id
assert prefs.pinned_at
end
test "handles multiple guest memberships with same team properly (regression)" do
user = new_user()
owner = new_user()
site1 = new_site(owner: owner)
site2 = new_site(owner: owner)
add_guest(site1, user: user, role: :viewer)
add_guest(site2, user: user, role: :viewer)
assert {:ok, prefs} = Sites.toggle_pin(user, site1)
assert prefs.site_id == site1.id
assert prefs.user_id == user.id
assert prefs.pinned_at
end
test "returns error when pins limit hit" do
user = new_user()
for _ <- 1..9 do
site = new_site(owner: user)
assert {:ok, _} = Sites.toggle_pin(user, site)
end
site = new_site(owner: user)
assert {:error, :too_many_pins} = Sites.toggle_pin(user, site)
end
end
end