Add models and migrations

This commit is contained in:
Mirai Kumiko 2025-06-06 16:07:04 +02:00
parent 182523d36d
commit 9e542bc790
Signed by: miraikumiko
GPG key ID: 3F178B1B5E0CB278
33 changed files with 597 additions and 125 deletions

View file

@ -20,12 +20,12 @@ defmodule Nulla.ActivityPub do
indexable: "toot:indexable",
attributionDomains: %{"@id" => "toot:attributionDomains", "@type" => "@id"},
Hashtag: "as:Hashtag",
focalPoint: %{"@container" => "@list", "@id" => "toot:focalPoint"}
vcard: "http://www.w3.org/2006/vcard/ns#"
)
]
end
@spec ap_user(String.t(), Nulla.Users.User.t()) :: Jason.OrderedObject.t()
@spec ap_user(String.t(), Nulla.Models.User.t()) :: Jason.OrderedObject.t()
def ap_user(domain, user) do
Jason.OrderedObject.new([
"@context": context(),
@ -81,4 +81,41 @@ defmodule Nulla.ActivityPub do
"vcard:Address": user.location
])
end
@spec note(String.t(), Nulla.Models.User.t(), Nulla.Models.Note.t()) :: Jason.OrderedObject.t()
def note(domain, user, note) do
Jason.OrderedObject.new([
"@context": [
"https://www.w3.org/ns/activitystreams",
Jason.OrderedObject.new(
sensitive: "as:sensitive"
)
],
id: "https://#{domain}/@#{user.username}/#{note.id}",
type: "Note",
summary: nil,
inReplyTo: nil,
published: note.inserted_at,
url: "https://#{domain}/@#{user.username}/#{note.id}",
attributedTo: "https://#{domain}/@#{user.username}",
to: [
"https://www.w3.org/ns/activitystreams#Public"
],
cc: [
"https://#{domain}/@#{user.username}/followers"
],
sensetive: false,
content: note.content,
contentMap: Jason.OrderedObject.new(
"#{note.language}": "<p>@rf@mastodonsocial.ru Вниманию новичкам!</p><p>Вам небольшое руководство о том, как импротировать пост, которого нет в вашей ленте.</p>"
),
attachment: [
Jason.OrderedObject.new(
type: "Document",
mediaType: "video/mp4",
url: "https://mastodon.ml/system/media_attachments/files/000/040/494/original/8c06de179c11daea.mp4"
)
]
])
end
end

View file

@ -0,0 +1,23 @@
defmodule Nulla.Models.Bookmark do
use Ecto.Schema
import Ecto.Changeset
import Ecto.Query
alias Nulla.Repo
alias Nulla.Models.Bookmark
schema "bookmarks" do
field :url, :string
field :user_id, :id
timestamps(type: :utc_datetime)
end
@doc false
def changeset(bookmark, attrs) do
bookmark
|> cast(attrs, [:url, :user_id])
|> validate_required([:url, :user_id])
end
def get_all_bookmarks!(user_id), do: Repo.all(from n in Bookmark, where: n.user_id == ^user_id)
end

View file

@ -0,0 +1,19 @@
defmodule Nulla.Models.Follow do
use Ecto.Schema
import Ecto.Changeset
schema "follows" do
belongs_to :user, Nulla.Models.User
belongs_to :target, Nulla.Models.User
timestamps()
end
@doc false
def changeset(follow, attrs) do
follow
|> cast(attrs, [:user_id, :target_id])
|> validate_required([:user_id, :target_id])
|> unique_constraint([:user_id, :target_id])
end
end

View file

@ -0,0 +1,19 @@
defmodule Nulla.Models.Hashtag do
use Ecto.Schema
import Ecto.Changeset
schema "hashtags" do
field :tag, :string
field :usage_count, :integer, default: 0
timestamps()
end
@doc false
def changeset(hashtag, attrs) do
hashtag
|> cast(attrs, [:tag, :usage_count])
|> validate_required([:tag])
|> unique_constraint(:tag)
end
end

View file

@ -1,7 +1,8 @@
defmodule Nulla.InstanceSettings do
defmodule Nulla.Models.InstanceSettings do
use Ecto.Schema
import Ecto.Changeset
alias Nulla.Repo
alias Nulla.Models.InstanceSettings
schema "instance_settings" do
field :name, :string, default: "Nulla"
@ -10,14 +11,16 @@ defmodule Nulla.InstanceSettings do
field :registration, :boolean, default: false
field :max_characters, :integer, default: 5000
field :max_upload_size, :integer, default: 50
field :public_key, :string
field :private_key, :string
end
@doc false
def changeset(instance_settings, attrs) do
instance_settings
|> cast(attrs, [:name, :description, :domain, :registration, :max_characters, :max_upload_size])
|> validate_required([:name, :description, :domain, :registration, :max_characters, :max_upload_size])
|> cast(attrs, [:name, :description, :domain, :registration, :max_characters, :max_upload_size, :public_key, :private_key])
|> validate_required([:name, :description, :domain, :registration, :max_characters, :max_upload_size, :public_key, :private_key])
end
def get_instance_settings!, do: Repo.one!(Nulla.InstanceSettings)
def get_instance_settings!, do: Repo.one!(InstanceSettings)
end

View file

@ -0,0 +1,20 @@
defmodule Nulla.Models.MediaAttachment do
use Ecto.Schema
import Ecto.Changeset
schema "media_attachments" do
field :file, :string
field :mime_type, :string
field :description, :string
belongs_to :note, Nulla.Models.Note
timestamps(type: :utc_datetime)
end
def changeset(media, attrs) do
media
|> cast(attrs, [:note_id, :file, :mime_type, :description])
|> validate_required([:note_id, :file])
end
end

View file

@ -0,0 +1,23 @@
defmodule Nulla.Models.ModerationLog do
use Ecto.Schema
import Ecto.Changeset
schema "moderation_logs" do
field :target_type, :string
field :target_id, :string
field :action, :string
field :reason, :string
field :metadata, :map
belongs_to :moderator, Nulla.Models.User
timestamps()
end
@doc false
def changeset(moderation_log, attrs) do
moderation_log
|> cast(attrs, [:moderator_id, :target_type, :target_id, :action, :reason, :metadata])
|> validate_required([:moderator_id, :target_type, :target_id, :action])
end
end

29
lib/nulla/models/note.ex Normal file
View file

@ -0,0 +1,29 @@
defmodule Nulla.Models.Note do
use Ecto.Schema
import Ecto.Changeset
import Ecto.Query
alias Nulla.Repo
alias Nulla.Models.Note
schema "notes" do
field :content, :string
field :visibility, Ecto.Enum, values: [:public, :unlisted, :followers, :private], default: :public
field :sensitive, :boolean, default: false
field :language, :string
field :in_reply_to, :string
belongs_to :user, Nulla.Models.User
has_many :media_attachments, Nulla.Models.MediaAttachment
timestamps(type: :utc_datetime)
end
@doc false
def changeset(note, attrs) do
note
|> cast(attrs, [:content, :visibility, :sensitive, :language, :in_reply_to, :user_id])
|> validate_required([:content, :visibility, :sensitive, :language, :in_reply_to, :user_id])
end
def get_all_notes!(user_id), do: Repo.all(from n in Note, where: n.user_id == ^user_id)
end

View file

@ -0,0 +1,22 @@
defmodule Nulla.Models.Notification do
use Ecto.Schema
import Ecto.Changeset
schema "notifications" do
field :type, :string
field :data, :map
field :read, :boolean, default: false
belongs_to :user, Nulla.Models.User
belongs_to :actor, Nulla.Models.User
timestamps()
end
@doc false
def changeset(notification, attrs) do
notification
|> cast(attrs, [:user_id, :actor_id, :type, :data, :read])
|> validate_required([:user_id, :type])
end
end

View file

@ -0,0 +1,21 @@
defmodule Nulla.Models.Session do
use Ecto.Schema
import Ecto.Changeset
schema "sessions" do
field :token, :string
field :user_agent, :string
field :ip, :string
belongs_to :user, Nulla.Models.User
timestamps(type: :utc_datetime)
end
def changeset(session, attrs) do
session
|> cast(attrs, [:user_id, :token, :user_agent, :ip])
|> validate_required([:user_id, :token])
|> unique_constraint(:token)
end
end

View file

@ -1,13 +1,14 @@
defmodule Nulla.Users.User do
defmodule Nulla.Models.User do
use Ecto.Schema
import Ecto.Changeset
alias Nulla.Repo
alias Nulla.Models.User
schema "users" do
field :username, :string
field :email, :string
field :password, :string
field :is_moderator, :boolean, default: false
field :realname, :string
field :bio, :string
field :location, :string
@ -24,6 +25,10 @@ defmodule Nulla.Users.User do
field :avatar, :string
field :banner, :string
has_many :user_sessions, Nulla.Models.Session
has_many :notes, Nulla.Models.Note
has_many :media_attachments, through: [:notes, :media_attachments]
timestamps(type: :utc_datetime)
end
@ -33,4 +38,6 @@ defmodule Nulla.Users.User do
|> cast(attrs, [:username, :email, :password, :is_moderator, :realname, :bio, :location, :birthday, :fields, :follow_approval, :is_bot, :is_discoverable, :is_indexable, :is_memorial, :private_key, :public_key, :avatar, :banner])
|> validate_required([:username, :email, :password, :is_moderator, :realname, :bio, :location, :birthday, :fields, :follow_approval, :is_bot, :is_discoverable, :is_indexable, :is_memorial, :private_key, :public_key, :avatar, :banner])
end
def get_user_by_username!(username), do: Repo.get_by!(User, username: username)
end

View file

@ -1,106 +0,0 @@
defmodule Nulla.Users do
@moduledoc """
The Users context.
"""
import Ecto.Query, warn: false
alias Nulla.Repo
alias Nulla.Users.User
@doc """
Returns the list of users.
## Examples
iex> list_users()
[%User{}, ...]
"""
def list_users do
Repo.all(User)
end
@doc """
Gets a single user.
Raises `Ecto.NoResultsError` if the User does not exist.
## Examples
iex> get_user!(123)
%User{}
iex> get_user!(456)
** (Ecto.NoResultsError)
"""
def get_user!(id), do: Repo.get!(User, id)
def get_user_by_username!(username), do: Repo.get_by!(User, username: username)
@doc """
Creates a user.
## Examples
iex> create_user(%{field: value})
{:ok, %User{}}
iex> create_user(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_user(attrs \\ %{}) do
%User{}
|> User.changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a user.
## Examples
iex> update_user(user, %{field: new_value})
{:ok, %User{}}
iex> update_user(user, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_user(%User{} = user, attrs) do
user
|> User.changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a user.
## Examples
iex> delete_user(user)
{:ok, %User{}}
iex> delete_user(user)
{:error, %Ecto.Changeset{}}
"""
def delete_user(%User{} = user) do
Repo.delete(user)
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking user changes.
## Examples
iex> change_user(user)
%Ecto.Changeset{data: %User{}}
"""
def change_user(%User{} = user, attrs \\ %{}) do
User.changeset(user, attrs)
end
end