Compare commits
No commits in common. "f05741edb5c66edc47d6c57b130748735e9d2099" and "2cbd29963efd300759c40fd7c454e2ec8f911653" have entirely different histories.
f05741edb5
...
2cbd29963e
20 changed files with 143 additions and 78 deletions
|
@ -23,7 +23,8 @@ config :nulla, NullaWeb.Endpoint,
|
||||||
live_view: [signing_salt: "jcAt5/U+"]
|
live_view: [signing_salt: "jcAt5/U+"]
|
||||||
|
|
||||||
# Snowflake configuration
|
# Snowflake configuration
|
||||||
config :nulla, :snowflake, worker_id: 1
|
config :nulla, :snowflake,
|
||||||
|
worker_id: 1
|
||||||
|
|
||||||
# Configures the mailer
|
# Configures the mailer
|
||||||
#
|
#
|
||||||
|
|
|
@ -304,16 +304,4 @@ defmodule Nulla.ActivityPub do
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec outbox(String.t(), String.t(), Integer.t()) :: Jason.OrderedObject.t()
|
|
||||||
def outbox(domain, username, total) do
|
|
||||||
Jason.OrderedObject.new(
|
|
||||||
"@context": "https://www.w3.org/ns/activitystreams",
|
|
||||||
id: "https://#{domain}/@#{username}/outbox",
|
|
||||||
type: "OrderedCollection",
|
|
||||||
totalItems: total,
|
|
||||||
first: "https://#{domain}/@#{username}/outbox?page=true",
|
|
||||||
last: "https://#{domain}/@#{username}/outbox?min_id=0&page=true"
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -33,9 +33,4 @@ defmodule Nulla.Models.Note do
|
||||||
def get_note!(id), do: Repo.get!(Note, id)
|
def get_note!(id), do: Repo.get!(Note, id)
|
||||||
|
|
||||||
def get_all_notes!(user_id), do: Repo.all(from n in Note, where: n.user_id == ^user_id)
|
def get_all_notes!(user_id), do: Repo.all(from n in Note, where: n.user_id == ^user_id)
|
||||||
|
|
||||||
def get_total_notes_count(user_id) do
|
|
||||||
from(n in Note, where: n.user_id == ^user_id)
|
|
||||||
|> Repo.aggregate(:count, :id)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
defmodule Nulla.Models.User do
|
defmodule Nulla.Models.User do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
import Ecto.Query
|
|
||||||
alias Nulla.Repo
|
alias Nulla.Repo
|
||||||
alias Nulla.Snowflake
|
alias Nulla.Snowflake
|
||||||
alias Nulla.Models.User
|
alias Nulla.Models.User
|
||||||
|
@ -9,7 +8,6 @@ defmodule Nulla.Models.User do
|
||||||
@primary_key {:id, :integer, autogenerate: false}
|
@primary_key {:id, :integer, autogenerate: false}
|
||||||
schema "users" do
|
schema "users" do
|
||||||
field :username, :string
|
field :username, :string
|
||||||
field :domain, :string
|
|
||||||
field :email, :string
|
field :email, :string
|
||||||
field :password, :string
|
field :password, :string
|
||||||
field :is_moderator, :boolean, default: false
|
field :is_moderator, :boolean, default: false
|
||||||
|
@ -17,7 +15,7 @@ defmodule Nulla.Models.User do
|
||||||
field :bio, :string
|
field :bio, :string
|
||||||
field :location, :string
|
field :location, :string
|
||||||
field :birthday, :date
|
field :birthday, :date
|
||||||
field :fields, {:array, :map}
|
field :fields, :map
|
||||||
field :tags, {:array, :string}
|
field :tags, {:array, :string}
|
||||||
field :follow_approval, :boolean, default: false
|
field :follow_approval, :boolean, default: false
|
||||||
field :is_bot, :boolean, default: false
|
field :is_bot, :boolean, default: false
|
||||||
|
@ -28,7 +26,6 @@ defmodule Nulla.Models.User do
|
||||||
field :public_key, :string
|
field :public_key, :string
|
||||||
field :avatar, :string
|
field :avatar, :string
|
||||||
field :banner, :string
|
field :banner, :string
|
||||||
field :last_active_at, :utc_datetime
|
|
||||||
|
|
||||||
has_many :user_sessions, Nulla.Models.Session
|
has_many :user_sessions, Nulla.Models.Session
|
||||||
has_many :notes, Nulla.Models.Note
|
has_many :notes, Nulla.Models.Note
|
||||||
|
@ -42,7 +39,6 @@ defmodule Nulla.Models.User do
|
||||||
user
|
user
|
||||||
|> cast(attrs, [
|
|> cast(attrs, [
|
||||||
:username,
|
:username,
|
||||||
:domain,
|
|
||||||
:email,
|
:email,
|
||||||
:password,
|
:password,
|
||||||
:is_moderator,
|
:is_moderator,
|
||||||
|
@ -59,12 +55,10 @@ defmodule Nulla.Models.User do
|
||||||
:private_key,
|
:private_key,
|
||||||
:public_key,
|
:public_key,
|
||||||
:avatar,
|
:avatar,
|
||||||
:banner,
|
:banner
|
||||||
:last_active_at
|
|
||||||
])
|
])
|
||||||
|> validate_required([
|
|> validate_required([
|
||||||
:username,
|
:username,
|
||||||
:domain,
|
|
||||||
:email,
|
:email,
|
||||||
:password,
|
:password,
|
||||||
:is_moderator,
|
:is_moderator,
|
||||||
|
@ -81,8 +75,7 @@ defmodule Nulla.Models.User do
|
||||||
:private_key,
|
:private_key,
|
||||||
:public_key,
|
:public_key,
|
||||||
:avatar,
|
:avatar,
|
||||||
:banner,
|
:banner
|
||||||
:last_active_at
|
|
||||||
])
|
])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -98,23 +91,4 @@ defmodule Nulla.Models.User do
|
||||||
def get_user_by_username(username), do: Repo.get_by(User, username: username)
|
def get_user_by_username(username), do: Repo.get_by(User, username: username)
|
||||||
|
|
||||||
def get_user_by_username!(username), do: Repo.get_by!(User, username: username)
|
def get_user_by_username!(username), do: Repo.get_by!(User, username: username)
|
||||||
|
|
||||||
def get_total_users_count(domain) do
|
|
||||||
Repo.aggregate(from(u in User, where: u.domain == ^domain), :count, :id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_active_users_count(domain, days) do
|
|
||||||
cutoff = DateTime.add(DateTime.utc_now(), -days * 86400, :second)
|
|
||||||
|
|
||||||
from(u in User,
|
|
||||||
where: u.domain == ^domain and u.last_active_at > ^cutoff
|
|
||||||
)
|
|
||||||
|> Repo.aggregate(:count, :id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def update_last_active(user) do
|
|
||||||
user
|
|
||||||
|> Ecto.Changeset.change(last_active_at: DateTime.utc_now())
|
|
||||||
|> Repo.update()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,6 +3,14 @@ defmodule NullaWeb.UserHTML do
|
||||||
|
|
||||||
embed_templates "templates/user/*"
|
embed_templates "templates/user/*"
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Renders a user form.
|
||||||
|
"""
|
||||||
|
attr :changeset, Ecto.Changeset, required: true
|
||||||
|
attr :action, :string, required: true
|
||||||
|
|
||||||
|
def user_form(assigns)
|
||||||
|
|
||||||
def format_birthdate(date) do
|
def format_birthdate(date) do
|
||||||
formatted = Date.to_string(date) |> String.replace("-", "/")
|
formatted = Date.to_string(date) |> String.replace("-", "/")
|
||||||
age = Timex.diff(Timex.today(), date, :years)
|
age = Timex.diff(Timex.today(), date, :years)
|
||||||
|
@ -76,3 +84,17 @@ defmodule NullaWeb.UserHTML do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defmodule NullaWeb.NoteHTML do
|
||||||
|
use NullaWeb, :html
|
||||||
|
|
||||||
|
embed_templates "templates/note/*"
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Renders a note form.
|
||||||
|
"""
|
||||||
|
attr :changeset, Ecto.Changeset, required: true
|
||||||
|
attr :action, :string, required: true
|
||||||
|
|
||||||
|
def note_form(assigns)
|
||||||
|
end
|
||||||
|
|
8
lib/nulla_web/components/templates/note/edit.html.heex
Normal file
8
lib/nulla_web/components/templates/note/edit.html.heex
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<.header>
|
||||||
|
Edit Note {@note.id}
|
||||||
|
<:subtitle>Use this form to manage note records in your database.</:subtitle>
|
||||||
|
</.header>
|
||||||
|
|
||||||
|
<.note_form changeset={@changeset} action={~p"/notes/#{@note}"} />
|
||||||
|
|
||||||
|
<.back navigate={~p"/notes"}>Back to notes</.back>
|
23
lib/nulla_web/components/templates/note/index.html.heex
Normal file
23
lib/nulla_web/components/templates/note/index.html.heex
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<.header>
|
||||||
|
Listing Notes
|
||||||
|
<:actions>
|
||||||
|
<.link href={~p"/notes/new"}>
|
||||||
|
<.button>New Note</.button>
|
||||||
|
</.link>
|
||||||
|
</:actions>
|
||||||
|
</.header>
|
||||||
|
|
||||||
|
<.table id="notes" rows={@notes} row_click={&JS.navigate(~p"/notes/#{&1}")}>
|
||||||
|
<:col :let={note} label="Content">{note.content}</:col>
|
||||||
|
<:action :let={note}>
|
||||||
|
<div class="sr-only">
|
||||||
|
<.link navigate={~p"/notes/#{note}"}>Show</.link>
|
||||||
|
</div>
|
||||||
|
<.link navigate={~p"/notes/#{note}/edit"}>Edit</.link>
|
||||||
|
</:action>
|
||||||
|
<:action :let={note}>
|
||||||
|
<.link href={~p"/notes/#{note}"} method="delete" data-confirm="Are you sure?">
|
||||||
|
Delete
|
||||||
|
</.link>
|
||||||
|
</:action>
|
||||||
|
</.table>
|
8
lib/nulla_web/components/templates/note/new.html.heex
Normal file
8
lib/nulla_web/components/templates/note/new.html.heex
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<.header>
|
||||||
|
New Note
|
||||||
|
<:subtitle>Use this form to manage note records in your database.</:subtitle>
|
||||||
|
</.header>
|
||||||
|
|
||||||
|
<.note_form changeset={@changeset} action={~p"/notes"} />
|
||||||
|
|
||||||
|
<.back navigate={~p"/notes"}>Back to notes</.back>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<.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[:content]} type="text" label="Content" />
|
||||||
|
<:actions>
|
||||||
|
<.button>Save Note</.button>
|
||||||
|
</:actions>
|
||||||
|
</.simple_form>
|
15
lib/nulla_web/components/templates/note/show.html.heex
Normal file
15
lib/nulla_web/components/templates/note/show.html.heex
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<.header>
|
||||||
|
Note {@note.id}
|
||||||
|
<:subtitle>This is a note record from your database.</:subtitle>
|
||||||
|
<:actions>
|
||||||
|
<.link href={~p"/notes/#{@note}/edit"}>
|
||||||
|
<.button>Edit note</.button>
|
||||||
|
</.link>
|
||||||
|
</:actions>
|
||||||
|
</.header>
|
||||||
|
|
||||||
|
<.list>
|
||||||
|
<:item title="Content">{@note.content}</:item>
|
||||||
|
</.list>
|
||||||
|
|
||||||
|
<.back navigate={~p"/notes"}>Back to notes</.back>
|
8
lib/nulla_web/components/templates/user/edit.html.heex
Normal file
8
lib/nulla_web/components/templates/user/edit.html.heex
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<.header>
|
||||||
|
Edit User {@user.id}
|
||||||
|
<:subtitle>Use this form to manage user records in your database.</:subtitle>
|
||||||
|
</.header>
|
||||||
|
|
||||||
|
<.user_form changeset={@changeset} action={~p"/users/#{@user}"} />
|
||||||
|
|
||||||
|
<.back navigate={~p"/users"}>Back to users</.back>
|
23
lib/nulla_web/components/templates/user/index.html.heex
Normal file
23
lib/nulla_web/components/templates/user/index.html.heex
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<.header>
|
||||||
|
Listing Users
|
||||||
|
<:actions>
|
||||||
|
<.link href={~p"/users/new"}>
|
||||||
|
<.button>New User</.button>
|
||||||
|
</.link>
|
||||||
|
</:actions>
|
||||||
|
</.header>
|
||||||
|
|
||||||
|
<.table id="users" rows={@users} row_click={&JS.navigate(~p"/users/#{&1}")}>
|
||||||
|
<:col :let={user} label="Username">{user.username}</:col>
|
||||||
|
<:action :let={user}>
|
||||||
|
<div class="sr-only">
|
||||||
|
<.link navigate={~p"/users/#{user}"}>Show</.link>
|
||||||
|
</div>
|
||||||
|
<.link navigate={~p"/users/#{user}/edit"}>Edit</.link>
|
||||||
|
</:action>
|
||||||
|
<:action :let={user}>
|
||||||
|
<.link href={~p"/users/#{user}"} method="delete" data-confirm="Are you sure?">
|
||||||
|
Delete
|
||||||
|
</.link>
|
||||||
|
</:action>
|
||||||
|
</.table>
|
8
lib/nulla_web/components/templates/user/new.html.heex
Normal file
8
lib/nulla_web/components/templates/user/new.html.heex
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<.header>
|
||||||
|
New User
|
||||||
|
<:subtitle>Use this form to manage user records in your database.</:subtitle>
|
||||||
|
</.header>
|
||||||
|
|
||||||
|
<.user_form changeset={@changeset} action={~p"/users"} />
|
||||||
|
|
||||||
|
<.back navigate={~p"/users"}>Back to users</.back>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<.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[:username]} type="text" label="Username" />
|
||||||
|
<:actions>
|
||||||
|
<.button>Save User</.button>
|
||||||
|
</:actions>
|
||||||
|
</.simple_form>
|
|
@ -14,16 +14,11 @@ defmodule NullaWeb.NodeinfoController do
|
||||||
|
|
||||||
def show(conn, _params) do
|
def show(conn, _params) do
|
||||||
version = Application.spec(:nulla, :vsn) |> to_string()
|
version = Application.spec(:nulla, :vsn) |> to_string()
|
||||||
instance_settings = InstanceSettings.get_instance_settings!()
|
|
||||||
domain = instance_settings.domain
|
|
||||||
total = User.get_total_users_count(domain)
|
|
||||||
month = User.get_active_users_count(domain, 30)
|
|
||||||
halfyear = User.get_active_users_count(domain, 180)
|
|
||||||
|
|
||||||
users = %{
|
users = %{
|
||||||
total: total,
|
total: 0,
|
||||||
month: month,
|
month: 0,
|
||||||
halfyear: halfyear
|
halfyear: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
instance_settings = InstanceSettings.get_instance_settings!()
|
instance_settings = InstanceSettings.get_instance_settings!()
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
defmodule NullaWeb.OutboxController do
|
|
||||||
use NullaWeb, :controller
|
|
||||||
alias Nulla.ActivityPub
|
|
||||||
alias Nulla.Models.User
|
|
||||||
alias Nulla.Models.Note
|
|
||||||
alias Nulla.Models.InstanceSettings
|
|
||||||
|
|
||||||
def show(conn, %{"username" => username}) do
|
|
||||||
instance_settings = InstanceSettings.get_instance_settings!()
|
|
||||||
domain = instance_settings.domain
|
|
||||||
user = User.get_user_by_username!(username)
|
|
||||||
total = Note.get_total_notes_count(user.id)
|
|
||||||
|
|
||||||
conn
|
|
||||||
|> put_resp_content_type("application/activity+json")
|
|
||||||
|> send_resp(200, Jason.encode!(ActivityPub.outbox(domain, username, total)))
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -16,7 +16,7 @@ defmodule NullaWeb.UserController do
|
||||||
if accept in ["application/activity+json", "application/ld+json"] do
|
if accept in ["application/activity+json", "application/ld+json"] do
|
||||||
conn
|
conn
|
||||||
|> put_resp_content_type("application/activity+json")
|
|> put_resp_content_type("application/activity+json")
|
||||||
|> send_resp(200, Jason.encode!(ActivityPub.user(domain, user)))
|
|> send_resp(200, ActivityPub.user(domain, user))
|
||||||
else
|
else
|
||||||
following = Utils.count_following_by_username!(user.username)
|
following = Utils.count_following_by_username!(user.username)
|
||||||
followers = Utils.count_followers_by_username!(user.username)
|
followers = Utils.count_followers_by_username!(user.username)
|
||||||
|
|
|
@ -22,7 +22,6 @@ defmodule NullaWeb.Router do
|
||||||
get "/nodeinfo/2.0", NodeinfoController, :show
|
get "/nodeinfo/2.0", NodeinfoController, :show
|
||||||
|
|
||||||
get "/@:username", UserController, :show
|
get "/@:username", UserController, :show
|
||||||
get "/@:username/outbox", OutboxController, :show
|
|
||||||
get "/@:username/following", FollowController, :following
|
get "/@:username/following", FollowController, :following
|
||||||
get "/@:username/followers", FollowController, :followers
|
get "/@:username/followers", FollowController, :followers
|
||||||
get "/@:username/:note_id", NoteController, :show
|
get "/@:username/:note_id", NoteController, :show
|
||||||
|
|
|
@ -5,7 +5,6 @@ defmodule Nulla.Repo.Migrations.CreateUsers do
|
||||||
create table(:users, primary_key: false) do
|
create table(:users, primary_key: false) do
|
||||||
add :id, :bigint, primary_key: true
|
add :id, :bigint, primary_key: true
|
||||||
add :username, :string, null: false, unique: true
|
add :username, :string, null: false, unique: true
|
||||||
add :domain, :string, null: false
|
|
||||||
add :email, :string
|
add :email, :string
|
||||||
add :password, :string
|
add :password, :string
|
||||||
add :is_moderator, :boolean, default: false, null: false
|
add :is_moderator, :boolean, default: false, null: false
|
||||||
|
@ -13,7 +12,7 @@ defmodule Nulla.Repo.Migrations.CreateUsers do
|
||||||
add :bio, :text
|
add :bio, :text
|
||||||
add :location, :string
|
add :location, :string
|
||||||
add :birthday, :date
|
add :birthday, :date
|
||||||
add :fields, :jsonb, default: "[]", null: false
|
add :fields, :map
|
||||||
add :tags, {:array, :string}
|
add :tags, {:array, :string}
|
||||||
add :follow_approval, :boolean, default: false, null: false
|
add :follow_approval, :boolean, default: false, null: false
|
||||||
add :is_bot, :boolean, default: false, null: false
|
add :is_bot, :boolean, default: false, null: false
|
||||||
|
@ -24,7 +23,6 @@ defmodule Nulla.Repo.Migrations.CreateUsers do
|
||||||
add :public_key, :string, null: false
|
add :public_key, :string, null: false
|
||||||
add :avatar, :string
|
add :avatar, :string
|
||||||
add :banner, :string
|
add :banner, :string
|
||||||
add :last_active_at, :utc_datetime
|
|
||||||
|
|
||||||
timestamps(type: :utc_datetime)
|
timestamps(type: :utc_datetime)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue