diff --git a/config/config.exs b/config/config.exs index c3983d9..fc9357b 100644 --- a/config/config.exs +++ b/config/config.exs @@ -23,7 +23,8 @@ config :nulla, NullaWeb.Endpoint, live_view: [signing_salt: "jcAt5/U+"] # Snowflake configuration -config :nulla, :snowflake, worker_id: 1 +config :nulla, :snowflake, + worker_id: 1 # Configures the mailer # diff --git a/lib/nulla/activitypub.ex b/lib/nulla/activitypub.ex index ec6332e..019aef8 100644 --- a/lib/nulla/activitypub.ex +++ b/lib/nulla/activitypub.ex @@ -304,16 +304,4 @@ defmodule Nulla.ActivityPub do ) ) 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 diff --git a/lib/nulla/keygen.ex b/lib/nulla/key_gen.ex similarity index 100% rename from lib/nulla/keygen.ex rename to lib/nulla/key_gen.ex diff --git a/lib/nulla/models/note.ex b/lib/nulla/models/note.ex index 83e1eb5..efaf328 100644 --- a/lib/nulla/models/note.ex +++ b/lib/nulla/models/note.ex @@ -33,9 +33,4 @@ defmodule Nulla.Models.Note do 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_total_notes_count(user_id) do - from(n in Note, where: n.user_id == ^user_id) - |> Repo.aggregate(:count, :id) - end end diff --git a/lib/nulla/models/user.ex b/lib/nulla/models/user.ex index ce1ce22..b3ef7ce 100644 --- a/lib/nulla/models/user.ex +++ b/lib/nulla/models/user.ex @@ -1,7 +1,6 @@ defmodule Nulla.Models.User do use Ecto.Schema import Ecto.Changeset - import Ecto.Query alias Nulla.Repo alias Nulla.Snowflake alias Nulla.Models.User @@ -9,7 +8,6 @@ defmodule Nulla.Models.User do @primary_key {:id, :integer, autogenerate: false} schema "users" do field :username, :string - field :domain, :string field :email, :string field :password, :string field :is_moderator, :boolean, default: false @@ -17,7 +15,7 @@ defmodule Nulla.Models.User do field :bio, :string field :location, :string field :birthday, :date - field :fields, {:array, :map} + field :fields, :map field :tags, {:array, :string} field :follow_approval, :boolean, default: false field :is_bot, :boolean, default: false @@ -28,7 +26,6 @@ defmodule Nulla.Models.User do field :public_key, :string field :avatar, :string field :banner, :string - field :last_active_at, :utc_datetime has_many :user_sessions, Nulla.Models.Session has_many :notes, Nulla.Models.Note @@ -42,7 +39,6 @@ defmodule Nulla.Models.User do user |> cast(attrs, [ :username, - :domain, :email, :password, :is_moderator, @@ -59,12 +55,10 @@ defmodule Nulla.Models.User do :private_key, :public_key, :avatar, - :banner, - :last_active_at + :banner ]) |> validate_required([ :username, - :domain, :email, :password, :is_moderator, @@ -81,8 +75,7 @@ defmodule Nulla.Models.User do :private_key, :public_key, :avatar, - :banner, - :last_active_at + :banner ]) 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_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 diff --git a/lib/nulla_web/components/templates.ex b/lib/nulla_web/components/templates.ex index acec111..87fc303 100644 --- a/lib/nulla_web/components/templates.ex +++ b/lib/nulla_web/components/templates.ex @@ -3,6 +3,14 @@ defmodule NullaWeb.UserHTML do 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 formatted = Date.to_string(date) |> String.replace("-", "/") age = Timex.diff(Timex.today(), date, :years) @@ -76,3 +84,17 @@ defmodule NullaWeb.UserHTML do 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 diff --git a/lib/nulla_web/components/templates/note/edit.html.heex b/lib/nulla_web/components/templates/note/edit.html.heex new file mode 100644 index 0000000..3bef388 --- /dev/null +++ b/lib/nulla_web/components/templates/note/edit.html.heex @@ -0,0 +1,8 @@ +<.header> + Edit Note {@note.id} + <:subtitle>Use this form to manage note records in your database. + + +<.note_form changeset={@changeset} action={~p"/notes/#{@note}"} /> + +<.back navigate={~p"/notes"}>Back to notes diff --git a/lib/nulla_web/components/templates/note/index.html.heex b/lib/nulla_web/components/templates/note/index.html.heex new file mode 100644 index 0000000..ffeedbc --- /dev/null +++ b/lib/nulla_web/components/templates/note/index.html.heex @@ -0,0 +1,23 @@ +<.header> + Listing Notes + <:actions> + <.link href={~p"/notes/new"}> + <.button>New Note + + + + +<.table id="notes" rows={@notes} row_click={&JS.navigate(~p"/notes/#{&1}")}> + <:col :let={note} label="Content">{note.content} + <:action :let={note}> +
+ <.link navigate={~p"/notes/#{note}"}>Show +
+ <.link navigate={~p"/notes/#{note}/edit"}>Edit + + <:action :let={note}> + <.link href={~p"/notes/#{note}"} method="delete" data-confirm="Are you sure?"> + Delete + + + diff --git a/lib/nulla_web/components/templates/note/new.html.heex b/lib/nulla_web/components/templates/note/new.html.heex new file mode 100644 index 0000000..4cf47a4 --- /dev/null +++ b/lib/nulla_web/components/templates/note/new.html.heex @@ -0,0 +1,8 @@ +<.header> + New Note + <:subtitle>Use this form to manage note records in your database. + + +<.note_form changeset={@changeset} action={~p"/notes"} /> + +<.back navigate={~p"/notes"}>Back to notes diff --git a/lib/nulla_web/components/templates/note/note_form.html.heex b/lib/nulla_web/components/templates/note/note_form.html.heex new file mode 100644 index 0000000..da6ac0f --- /dev/null +++ b/lib/nulla_web/components/templates/note/note_form.html.heex @@ -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. + + <.input field={f[:content]} type="text" label="Content" /> + <:actions> + <.button>Save Note + + diff --git a/lib/nulla_web/components/templates/note/show.html.heex b/lib/nulla_web/components/templates/note/show.html.heex new file mode 100644 index 0000000..d7f2f70 --- /dev/null +++ b/lib/nulla_web/components/templates/note/show.html.heex @@ -0,0 +1,15 @@ +<.header> + Note {@note.id} + <:subtitle>This is a note record from your database. + <:actions> + <.link href={~p"/notes/#{@note}/edit"}> + <.button>Edit note + + + + +<.list> + <:item title="Content">{@note.content} + + +<.back navigate={~p"/notes"}>Back to notes diff --git a/lib/nulla_web/components/templates/user/edit.html.heex b/lib/nulla_web/components/templates/user/edit.html.heex new file mode 100644 index 0000000..2f8aa66 --- /dev/null +++ b/lib/nulla_web/components/templates/user/edit.html.heex @@ -0,0 +1,8 @@ +<.header> + Edit User {@user.id} + <:subtitle>Use this form to manage user records in your database. + + +<.user_form changeset={@changeset} action={~p"/users/#{@user}"} /> + +<.back navigate={~p"/users"}>Back to users diff --git a/lib/nulla_web/components/templates/user/index.html.heex b/lib/nulla_web/components/templates/user/index.html.heex new file mode 100644 index 0000000..9eca5b7 --- /dev/null +++ b/lib/nulla_web/components/templates/user/index.html.heex @@ -0,0 +1,23 @@ +<.header> + Listing Users + <:actions> + <.link href={~p"/users/new"}> + <.button>New User + + + + +<.table id="users" rows={@users} row_click={&JS.navigate(~p"/users/#{&1}")}> + <:col :let={user} label="Username">{user.username} + <:action :let={user}> +
+ <.link navigate={~p"/users/#{user}"}>Show +
+ <.link navigate={~p"/users/#{user}/edit"}>Edit + + <:action :let={user}> + <.link href={~p"/users/#{user}"} method="delete" data-confirm="Are you sure?"> + Delete + + + diff --git a/lib/nulla_web/components/templates/user/new.html.heex b/lib/nulla_web/components/templates/user/new.html.heex new file mode 100644 index 0000000..9248fb0 --- /dev/null +++ b/lib/nulla_web/components/templates/user/new.html.heex @@ -0,0 +1,8 @@ +<.header> + New User + <:subtitle>Use this form to manage user records in your database. + + +<.user_form changeset={@changeset} action={~p"/users"} /> + +<.back navigate={~p"/users"}>Back to users diff --git a/lib/nulla_web/components/templates/user/user_form.html.heex b/lib/nulla_web/components/templates/user/user_form.html.heex new file mode 100644 index 0000000..6871618 --- /dev/null +++ b/lib/nulla_web/components/templates/user/user_form.html.heex @@ -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. + + <.input field={f[:username]} type="text" label="Username" /> + <:actions> + <.button>Save User + + diff --git a/lib/nulla_web/controllers/nodeinfo_controller.ex b/lib/nulla_web/controllers/nodeinfo_controller.ex index 46a3bed..92efc88 100644 --- a/lib/nulla_web/controllers/nodeinfo_controller.ex +++ b/lib/nulla_web/controllers/nodeinfo_controller.ex @@ -14,16 +14,11 @@ defmodule NullaWeb.NodeinfoController do def show(conn, _params) do 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 = %{ - total: total, - month: month, - halfyear: halfyear + total: 0, + month: 0, + halfyear: 0 } instance_settings = InstanceSettings.get_instance_settings!() diff --git a/lib/nulla_web/controllers/outbox_controller.ex b/lib/nulla_web/controllers/outbox_controller.ex deleted file mode 100644 index 55d13da..0000000 --- a/lib/nulla_web/controllers/outbox_controller.ex +++ /dev/null @@ -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 diff --git a/lib/nulla_web/controllers/user_controller.ex b/lib/nulla_web/controllers/user_controller.ex index d85d580..a5467e7 100644 --- a/lib/nulla_web/controllers/user_controller.ex +++ b/lib/nulla_web/controllers/user_controller.ex @@ -16,7 +16,7 @@ defmodule NullaWeb.UserController do if accept in ["application/activity+json", "application/ld+json"] do conn |> put_resp_content_type("application/activity+json") - |> send_resp(200, Jason.encode!(ActivityPub.user(domain, user))) + |> send_resp(200, ActivityPub.user(domain, user)) else following = Utils.count_following_by_username!(user.username) followers = Utils.count_followers_by_username!(user.username) diff --git a/lib/nulla_web/router.ex b/lib/nulla_web/router.ex index 6e50c78..ac27911 100644 --- a/lib/nulla_web/router.ex +++ b/lib/nulla_web/router.ex @@ -22,7 +22,6 @@ defmodule NullaWeb.Router do get "/nodeinfo/2.0", NodeinfoController, :show get "/@:username", UserController, :show - get "/@:username/outbox", OutboxController, :show get "/@:username/following", FollowController, :following get "/@:username/followers", FollowController, :followers get "/@:username/:note_id", NoteController, :show diff --git a/priv/repo/migrations/20250530110822_create_users.exs b/priv/repo/migrations/20250530110822_create_users.exs index 2b48cfa..b597c2f 100644 --- a/priv/repo/migrations/20250530110822_create_users.exs +++ b/priv/repo/migrations/20250530110822_create_users.exs @@ -5,7 +5,6 @@ defmodule Nulla.Repo.Migrations.CreateUsers do create table(:users, primary_key: false) do add :id, :bigint, primary_key: true add :username, :string, null: false, unique: true - add :domain, :string, null: false add :email, :string add :password, :string add :is_moderator, :boolean, default: false, null: false @@ -13,7 +12,7 @@ defmodule Nulla.Repo.Migrations.CreateUsers do add :bio, :text add :location, :string add :birthday, :date - add :fields, :jsonb, default: "[]", null: false + add :fields, :map add :tags, {:array, :string} add :follow_approval, :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 :avatar, :string add :banner, :string - add :last_active_at, :utc_datetime timestamps(type: :utc_datetime) end