commit
2e889ff3a4
14 changed files with 205 additions and 15 deletions
|
@ -64,3 +64,22 @@ document
|
||||||
window.localStorage.setItem("theme", "dark")
|
window.localStorage.setItem("theme", "dark")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
document
|
||||||
|
.querySelectorAll('textarea')
|
||||||
|
.forEach(e => e.addEventListener('keydown', function(e) {
|
||||||
|
if (e.key == 'Tab') {
|
||||||
|
e.preventDefault();
|
||||||
|
var start = this.selectionStart;
|
||||||
|
var end = this.selectionEnd;
|
||||||
|
|
||||||
|
// set textarea value to: text before caret + tab + text after caret
|
||||||
|
this.value = this.value.substring(0, start) +
|
||||||
|
"\t" + this.value.substring(end);
|
||||||
|
|
||||||
|
// put caret at right position again
|
||||||
|
this.selectionStart =
|
||||||
|
this.selectionEnd = start + 1;
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,10 @@ defmodule Chiya.Accounts do
|
||||||
|
|
||||||
alias Chiya.Accounts.{User, UserToken, UserNotifier}
|
alias Chiya.Accounts.{User, UserToken, UserNotifier}
|
||||||
|
|
||||||
|
defp preload_user(user) do
|
||||||
|
Repo.preload(user, [:tokens])
|
||||||
|
end
|
||||||
|
|
||||||
def has_user?() do
|
def has_user?() do
|
||||||
Repo.exists?(User)
|
Repo.exists?(User)
|
||||||
end
|
end
|
||||||
|
@ -240,6 +244,21 @@ defmodule Chiya.Accounts do
|
||||||
Repo.update(changeset)
|
Repo.update(changeset)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
## App Tokens
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Generates a application token.
|
||||||
|
"""
|
||||||
|
def generate_app_token(user, app_name, context) do
|
||||||
|
attrs = UserToken.build_app_token(user, app_name, context)
|
||||||
|
changeset = UserToken.app_token_changeset(%UserToken{}, attrs)
|
||||||
|
Repo.insert(changeset)
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete_app_token(id) do
|
||||||
|
Repo.delete(Repo.get(UserToken, id))
|
||||||
|
end
|
||||||
|
|
||||||
## Session
|
## Session
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
@ -256,7 +275,7 @@ defmodule Chiya.Accounts do
|
||||||
"""
|
"""
|
||||||
def get_user_by_session_token(token) do
|
def get_user_by_session_token(token) do
|
||||||
{:ok, query} = UserToken.verify_session_token_query(token)
|
{:ok, query} = UserToken.verify_session_token_query(token)
|
||||||
Repo.one(query)
|
Repo.one(query) |> preload_user()
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
|
|
@ -11,6 +11,8 @@ defmodule Chiya.Accounts.User do
|
||||||
|
|
||||||
field :user_image, ChiyaWeb.Uploaders.UserImage.Type
|
field :user_image, ChiyaWeb.Uploaders.UserImage.Type
|
||||||
|
|
||||||
|
has_many :tokens, Chiya.Accounts.UserToken
|
||||||
|
|
||||||
timestamps()
|
timestamps()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
defmodule Chiya.Accounts.UserToken do
|
defmodule Chiya.Accounts.UserToken do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
import Ecto.Changeset
|
||||||
alias Chiya.Accounts.UserToken
|
alias Chiya.Accounts.UserToken
|
||||||
|
|
||||||
@hash_algorithm :sha256
|
@hash_algorithm :sha256
|
||||||
|
@ -22,6 +23,23 @@ defmodule Chiya.Accounts.UserToken do
|
||||||
timestamps(updated_at: false)
|
timestamps(updated_at: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def build_app_token(user, app_name, context) do
|
||||||
|
token = :crypto.strong_rand_bytes(@rand_size)
|
||||||
|
|
||||||
|
%{
|
||||||
|
token: token,
|
||||||
|
context: context,
|
||||||
|
user_id: user.id,
|
||||||
|
sent_to: app_name
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def app_token_changeset(token, attrs) do
|
||||||
|
token
|
||||||
|
|> cast(attrs, [:context, :token, :sent_to, :user_id])
|
||||||
|
|> validate_required([:context, :token, :sent_to, :user_id])
|
||||||
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Generates a token that will be stored in a signed place,
|
Generates a token that will be stored in a signed place,
|
||||||
such as session or cookie. As they are signed, those
|
such as session or cookie. As they are signed, those
|
||||||
|
|
|
@ -21,6 +21,11 @@
|
||||||
icon: "hero-user-solid",
|
icon: "hero-user-solid",
|
||||||
name: "Identities"
|
name: "Identities"
|
||||||
},
|
},
|
||||||
|
%{
|
||||||
|
path: ~p"/admin/tokens",
|
||||||
|
icon: "hero-key-solid",
|
||||||
|
name: "Tokens"
|
||||||
|
},
|
||||||
%{
|
%{
|
||||||
path: ~p"/admin/settings",
|
path: ~p"/admin/settings",
|
||||||
icon: "hero-wrench-screwdriver-solid",
|
icon: "hero-wrench-screwdriver-solid",
|
||||||
|
|
|
@ -76,6 +76,7 @@
|
||||||
|
|
||||||
<ul class="list-disc list-inside">
|
<ul class="list-disc list-inside">
|
||||||
<li><a href="#"><del>Wiki</del></a></li>
|
<li><a href="#"><del>Wiki</del></a></li>
|
||||||
|
<li><a href={~p"/admin"}>Admin</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
47
lib/chiya_web/controllers/token_controller.ex
Normal file
47
lib/chiya_web/controllers/token_controller.ex
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
defmodule ChiyaWeb.TokenController do
|
||||||
|
use ChiyaWeb, :controller
|
||||||
|
|
||||||
|
alias Chiya.Accounts.UserToken
|
||||||
|
|
||||||
|
def index(conn, _params) do
|
||||||
|
tokens = conn.assigns.current_user.tokens
|
||||||
|
render(conn, :index, tokens: tokens)
|
||||||
|
end
|
||||||
|
|
||||||
|
def show(conn, %{"id" => id}) do
|
||||||
|
token_id = String.to_integer(id)
|
||||||
|
tokens = conn.assigns.current_user.tokens
|
||||||
|
token = Enum.find(tokens, fn t -> t.id == token_id end)
|
||||||
|
render(conn, :show, token: token)
|
||||||
|
end
|
||||||
|
|
||||||
|
def new(conn, _params) do
|
||||||
|
changeset =
|
||||||
|
UserToken.app_token_changeset(%UserToken{}, %{
|
||||||
|
user_id: conn.assigns.current_user.id,
|
||||||
|
context: "app"
|
||||||
|
})
|
||||||
|
|
||||||
|
render(conn, :new, changeset: changeset)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create(conn, %{"user_token" => %{"sent_to" => app_name, "context" => context}}) do
|
||||||
|
case Chiya.Accounts.generate_app_token(conn.assigns.current_user, app_name, context) do
|
||||||
|
{:ok, token} ->
|
||||||
|
conn
|
||||||
|
|> put_flash(:info, "token created successfully.")
|
||||||
|
|> redirect(to: ~p"/admin/tokens/#{token}")
|
||||||
|
|
||||||
|
{:error, %Ecto.Changeset{} = changeset} ->
|
||||||
|
render(conn, :new, changeset: changeset)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete(conn, %{"id" => id}) do
|
||||||
|
{:ok, _token} = Chiya.Accounts.delete_app_token(id)
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_flash(:info, "Token deleted successfully.")
|
||||||
|
|> redirect(to: ~p"/admin/tokens")
|
||||||
|
end
|
||||||
|
end
|
13
lib/chiya_web/controllers/token_html.ex
Normal file
13
lib/chiya_web/controllers/token_html.ex
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
defmodule ChiyaWeb.TokenHTML do
|
||||||
|
use ChiyaWeb, :html
|
||||||
|
|
||||||
|
embed_templates "token_html/*"
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Renders a token form.
|
||||||
|
"""
|
||||||
|
attr :changeset, Ecto.Changeset, required: true
|
||||||
|
attr :action, :string, required: true
|
||||||
|
|
||||||
|
def token_form(assigns)
|
||||||
|
end
|
8
lib/chiya_web/controllers/token_html/edit.html.heex
Normal file
8
lib/chiya_web/controllers/token_html/edit.html.heex
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<.header>
|
||||||
|
Edit Channel <%= @channel.id %>
|
||||||
|
<:subtitle>Use this form to manage channel records in your database.</:subtitle>
|
||||||
|
</.header>
|
||||||
|
|
||||||
|
<.token_form changeset={@changeset} action={~p"/admin/channels/#{@channel}"} />
|
||||||
|
|
||||||
|
<.back navigate={~p"/admin/channels"}>Back to channels</.back>
|
21
lib/chiya_web/controllers/token_html/index.html.heex
Normal file
21
lib/chiya_web/controllers/token_html/index.html.heex
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<.header>
|
||||||
|
<.icon name="hero-key" /> Tokens
|
||||||
|
<:subtitle>Tokens are like keys.</:subtitle>
|
||||||
|
<:actions>
|
||||||
|
<.link href={~p"/admin/tokens/new"}>
|
||||||
|
<.button>New Token</.button>
|
||||||
|
</.link>
|
||||||
|
</:actions>
|
||||||
|
</.header>
|
||||||
|
|
||||||
|
<.table id="tokens" rows={@tokens} row_click={&JS.navigate(~p"/admin/tokens/#{&1}")}>
|
||||||
|
<:col :let={token} label="Id"><%= token.id %></:col>
|
||||||
|
<:col :let={token} label="Context"><%= token.context %></:col>
|
||||||
|
<:col :let={token} label="App Name"><%= token.sent_to %></:col>
|
||||||
|
<:col :let={token} label="Created"><%= pretty_date(token.inserted_at) %></:col>
|
||||||
|
<:action :let={token}>
|
||||||
|
<.link href={~p"/admin/tokens/#{token}"} method="delete" data-confirm="Are you sure?">
|
||||||
|
Delete
|
||||||
|
</.link>
|
||||||
|
</:action>
|
||||||
|
</.table>
|
8
lib/chiya_web/controllers/token_html/new.html.heex
Normal file
8
lib/chiya_web/controllers/token_html/new.html.heex
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<.header>
|
||||||
|
New Token
|
||||||
|
<:subtitle>Use this form to create new token records in your database.</:subtitle>
|
||||||
|
</.header>
|
||||||
|
|
||||||
|
<.token_form changeset={@changeset} action={~p"/admin/tokens"} />
|
||||||
|
|
||||||
|
<.back navigate={~p"/admin/tokens"}>Back to channels</.back>
|
17
lib/chiya_web/controllers/token_html/show.html.heex
Normal file
17
lib/chiya_web/controllers/token_html/show.html.heex
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<.header>
|
||||||
|
Token <%= @token.id %>
|
||||||
|
<:subtitle>This is a token.</:subtitle>
|
||||||
|
<:actions></:actions>
|
||||||
|
</.header>
|
||||||
|
|
||||||
|
<.list>
|
||||||
|
<:item title="Id"><%= @token.id %></:item>
|
||||||
|
<:item title="App Name"><%= @token.sent_to %></:item>
|
||||||
|
<:item title="Context"><%= @token.context %></:item>
|
||||||
|
<:item title="Created"><%= @token.inserted_at %></:item>
|
||||||
|
<:item title="Value">
|
||||||
|
<p class="break-all"><%= :crypto.bytes_to_integer(@token.token) %></p>
|
||||||
|
</:item>
|
||||||
|
</.list>
|
||||||
|
|
||||||
|
<.back navigate={~p"/admin/tokens"}>Back to channels</.back>
|
11
lib/chiya_web/controllers/token_html/token_form.html.heex
Normal file
11
lib/chiya_web/controllers/token_html/token_form.html.heex
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<.simple_form :let={f} for={@changeset} action={@action}>
|
||||||
|
<.error :if={@changeset.action}>
|
||||||
|
Oops, something went wrong! Please check the errors below.
|
||||||
|
</.error>
|
||||||
|
<.input field={f[:context]} type="text" label="Context" />
|
||||||
|
<.input field={f[:sent_to]} type="text" label="Application" />
|
||||||
|
<.input field={f[:user_id]} type="hidden" />
|
||||||
|
<:actions>
|
||||||
|
<.button>Save Token</.button>
|
||||||
|
</:actions>
|
||||||
|
</.simple_form>
|
|
@ -73,6 +73,7 @@ defmodule ChiyaWeb.Router do
|
||||||
resources "/settings", SettingController, singleton: true
|
resources "/settings", SettingController, singleton: true
|
||||||
resources "/identities", IdentityController
|
resources "/identities", IdentityController
|
||||||
resources "/comments", CommentController, only: [:index, :show]
|
resources "/comments", CommentController, only: [:index, :show]
|
||||||
|
resources "/tokens", TokenController, only: [:index, :show, :new, :create, :delete]
|
||||||
|
|
||||||
get "/notes/import", NoteController, :import_prepare
|
get "/notes/import", NoteController, :import_prepare
|
||||||
post "/notes/import", NoteController, :import_run
|
post "/notes/import", NoteController, :import_run
|
||||||
|
|
Loading…
Reference in a new issue