devel #97
14 changed files with 205 additions and 15 deletions
|
@ -64,3 +64,22 @@ document
|
|||
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}
|
||||
|
||||
defp preload_user(user) do
|
||||
Repo.preload(user, [:tokens])
|
||||
end
|
||||
|
||||
def has_user?() do
|
||||
Repo.exists?(User)
|
||||
end
|
||||
|
@ -240,6 +244,21 @@ defmodule Chiya.Accounts do
|
|||
Repo.update(changeset)
|
||||
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
|
||||
|
||||
@doc """
|
||||
|
@ -256,7 +275,7 @@ defmodule Chiya.Accounts do
|
|||
"""
|
||||
def get_user_by_session_token(token) do
|
||||
{:ok, query} = UserToken.verify_session_token_query(token)
|
||||
Repo.one(query)
|
||||
Repo.one(query) |> preload_user()
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
|
|
@ -11,6 +11,8 @@ defmodule Chiya.Accounts.User do
|
|||
|
||||
field :user_image, ChiyaWeb.Uploaders.UserImage.Type
|
||||
|
||||
has_many :tokens, Chiya.Accounts.UserToken
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
defmodule Chiya.Accounts.UserToken do
|
||||
use Ecto.Schema
|
||||
import Ecto.Query
|
||||
import Ecto.Changeset
|
||||
alias Chiya.Accounts.UserToken
|
||||
|
||||
@hash_algorithm :sha256
|
||||
|
@ -22,6 +23,23 @@ defmodule Chiya.Accounts.UserToken do
|
|||
timestamps(updated_at: false)
|
||||
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 """
|
||||
Generates a token that will be stored in a signed place,
|
||||
such as session or cookie. As they are signed, those
|
||||
|
|
|
@ -21,6 +21,11 @@
|
|||
icon: "hero-user-solid",
|
||||
name: "Identities"
|
||||
},
|
||||
%{
|
||||
path: ~p"/admin/tokens",
|
||||
icon: "hero-key-solid",
|
||||
name: "Tokens"
|
||||
},
|
||||
%{
|
||||
path: ~p"/admin/settings",
|
||||
icon: "hero-wrench-screwdriver-solid",
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
|
||||
<ul class="list-disc list-inside">
|
||||
<li><a href="#"><del>Wiki</del></a></li>
|
||||
<li><a href={~p"/admin"}>Admin</a></li>
|
||||
</ul>
|
||||
</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 "/identities", IdentityController
|
||||
resources "/comments", CommentController, only: [:index, :show]
|
||||
resources "/tokens", TokenController, only: [:index, :show, :new, :create, :delete]
|
||||
|
||||
get "/notes/import", NoteController, :import_prepare
|
||||
post "/notes/import", NoteController, :import_run
|
||||
|
|
Loading…
Reference in a new issue