X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fuser_invite_token.ex;h=4cff1c515f3d6781e39f5eae197be34635862d5d;hb=a079ec3a3cdfd42d2cbd51c7698c2c87828e5778;hp=3ed39ddd36ef414fa581a9e7cacf5abb7646f7b5;hpb=0484f3a8b1ae2103d1d756e5c09f2bdb218a7207;p=akkoma diff --git a/lib/pleroma/user_invite_token.ex b/lib/pleroma/user_invite_token.ex index 3ed39ddd3..4cff1c515 100644 --- a/lib/pleroma/user_invite_token.ex +++ b/lib/pleroma/user_invite_token.ex @@ -1,5 +1,5 @@ # Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors +# Copyright © 2017-2021 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.UserInviteToken do @@ -10,113 +10,115 @@ defmodule Pleroma.UserInviteToken do alias Pleroma.Repo alias Pleroma.UserInviteToken + @type t :: %__MODULE__{} @type token :: String.t() schema "user_invite_tokens" do field(:token, :string) field(:used, :boolean, default: false) field(:max_use, :integer) - field(:expire_at, :date) - field(:uses, :integer) - field(:token_type) + field(:expires_at, :date) + field(:uses, :integer, default: 0) + field(:invite_type, :string) timestamps() end - def create_token(options \\ []) do + @spec create_invite(map()) :: {:ok, UserInviteToken.t()} + def create_invite(params \\ %{}) do + %UserInviteToken{} + |> cast(params, [:max_use, :expires_at]) + |> add_token() + |> assign_type() + |> Repo.insert() + end + + defp add_token(changeset) do token = :crypto.strong_rand_bytes(32) |> Base.url_encode64() + put_change(changeset, :token, token) + end - max_use = options[:max_use] - expire_at = options[:expire_at] + defp assign_type(%{changes: %{max_use: _max_use, expires_at: _expires_at}} = changeset) do + put_change(changeset, :invite_type, "reusable_date_limited") + end - token = - %UserInviteToken{ - used: false, - token: token, - max_use: max_use, - expire_at: expire_at, - uses: 0 - } - |> token_type() + defp assign_type(%{changes: %{expires_at: _expires_at}} = changeset) do + put_change(changeset, :invite_type, "date_limited") + end - Repo.insert(token) + defp assign_type(%{changes: %{max_use: _max_use}} = changeset) do + put_change(changeset, :invite_type, "reusable") end + defp assign_type(changeset), do: put_change(changeset, :invite_type, "one_time") + + @spec list_invites() :: [UserInviteToken.t()] def list_invites do query = from(u in UserInviteToken, order_by: u.id) Repo.all(query) end - def used_changeset(struct) do - struct - |> cast(%{}, []) - |> put_change(:used, true) + @spec update_invite!(UserInviteToken.t(), map()) :: UserInviteToken.t() | no_return() + def update_invite!(invite, changes) do + change(invite, changes) |> Repo.update!() end - @spec mark_as_used(token()) :: {:ok, UserInviteToken.t()} | {:error, token()} - def mark_as_used(token) do - with %{used: false} = token <- Repo.get_by(UserInviteToken, %{token: token}), - {:ok, token} <- Repo.update(used_changeset(token)) do - {:ok, token} - else - _e -> {:error, token} - end + @spec update_invite(UserInviteToken.t(), map()) :: + {:ok, UserInviteToken.t()} | {:error, Changeset.t()} + def update_invite(invite, changes) do + change(invite, changes) |> Repo.update() end - defp token_type(%{expire_at: nil, max_use: nil} = token), do: %{token | token_type: "one_time"} + @spec find_by_token!(token()) :: UserInviteToken.t() | no_return() + def find_by_token!(token), do: Repo.get_by!(UserInviteToken, token: token) - defp token_type(%{expire_at: _expire_at, max_use: nil} = token), - do: %{token | token_type: "date_limited"} - - defp token_type(%{expire_at: nil, max_use: _max_use} = token), - do: %{token | token_type: "reusable"} - - defp token_type(%{expire_at: _expire_at, max_use: _max_use} = token), - do: %{token | token_type: "reusable_date_limited"} - - @spec valid_token?(UserInviteToken.t()) :: boolean() - def valid_token?(%{token_type: "one_time"} = token) do - not token.used + @spec find_by_token(token()) :: {:ok, UserInviteToken.t()} | nil + def find_by_token(token) do + with %UserInviteToken{} = invite <- Repo.get_by(UserInviteToken, token: token) do + {:ok, invite} + end end - def valid_token?(%{token_type: "date_limited"} = token) do - not_overdue_date?(token) and not token.used + @spec valid_invite?(UserInviteToken.t()) :: boolean() + def valid_invite?(%{invite_type: "one_time"} = invite) do + not invite.used end - def valid_token?(%{token_type: "reusable"} = token) do - token.uses < token.max_use and not token.used + def valid_invite?(%{invite_type: "date_limited"} = invite) do + not_overdue_date?(invite) and not invite.used end - def valid_token?(%{token_type: "reusable_date_limited"} = token) do - not_overdue_date?(token) and token.uses < token.max_use and not token.used + def valid_invite?(%{invite_type: "reusable"} = invite) do + invite.uses < invite.max_use and not invite.used end - defp not_overdue_date?(%{expire_at: expire_at} = token) do - Date.compare(Date.utc_today(), expire_at) in [:lt, :eq] || - (Repo.update!(change(token, used: true)) && false) + def valid_invite?(%{invite_type: "reusable_date_limited"} = invite) do + not_overdue_date?(invite) and invite.uses < invite.max_use and not invite.used end - def update_usage(%{token_type: "date_limited"}), do: nil - - def update_usage(%{token_type: "one_time"} = token) do - UserInviteToken.mark_as_used(token.token) + defp not_overdue_date?(%{expires_at: expires_at}) do + Date.compare(Date.utc_today(), expires_at) in [:lt, :eq] end - def update_usage(%{token_type: token_type} = token) - when token_type == "reusable" or token_type == "reusable_date_limited" do - new_uses = token.uses + 1 + @spec update_usage!(UserInviteToken.t()) :: nil | UserInviteToken.t() | no_return() + def update_usage!(%{invite_type: "date_limited"}), do: nil + + def update_usage!(%{invite_type: "one_time"} = invite), + do: update_invite!(invite, %{used: true}) + def update_usage!(%{invite_type: invite_type} = invite) + when invite_type == "reusable" or invite_type == "reusable_date_limited" do changes = %{ - uses: new_uses + uses: invite.uses + 1 } changes = - if new_uses >= token.max_use do + if changes.uses >= invite.max_use do Map.put(changes, :used, true) else changes end - change(token, changes) |> Repo.update!() + update_invite!(invite, changes) end end