Skip to content

Commit

Permalink
chore: added support to student cycle info logging
Browse files Browse the repository at this point in the history
- created `StudentsCycleInfoLog` context
- created `StudentCycleInfoLog` schema in `StudentsCycleInfoLog` context
  • Loading branch information
endoooo committed Jan 6, 2025
1 parent 9923c50 commit afea763
Show file tree
Hide file tree
Showing 10 changed files with 304 additions and 28 deletions.
30 changes: 23 additions & 7 deletions lib/lanttern/students_cycle_info.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ defmodule Lanttern.StudentsCycleInfo do
alias Lanttern.Schools.Student
alias Lanttern.Repo

alias Lanttern.StudentsCycleInfoLog
alias Lanttern.StudentsCycleInfo.StudentCycleInfo
alias Lanttern.Schools.Class
alias Lanttern.Schools.Cycle
Expand Down Expand Up @@ -70,24 +71,33 @@ defmodule Lanttern.StudentsCycleInfo do
@doc """
Creates a student_cycle_info.
## Options:
- `:log_profile_id` - logs the operation, linked to given profile
## Examples
iex> create_student_cycle_info(%{field: value})
{:ok, %StudentCycleInfo{}}
iex> create_student_cycle_info(%{field: value})
{:ok, %StudentCycleInfo{}}
iex> create_student_cycle_info(%{field: bad_value})
{:error, %Ecto.Changeset{}}
iex> create_student_cycle_info(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_student_cycle_info(attrs \\ %{}) do
def create_student_cycle_info(attrs \\ %{}, opts \\ []) do
%StudentCycleInfo{}
|> StudentCycleInfo.changeset(attrs)
|> Repo.insert()
|> StudentsCycleInfoLog.maybe_create_student_cycle_info_log("CREATE", opts)
end

@doc """
Updates a student_cycle_info.
## Options:
- `:log_profile_id` - logs the operation, linked to given profile
## Examples
iex> update_student_cycle_info(student_cycle_info, %{field: new_value})
Expand All @@ -97,15 +107,20 @@ defmodule Lanttern.StudentsCycleInfo do
{:error, %Ecto.Changeset{}}
"""
def update_student_cycle_info(%StudentCycleInfo{} = student_cycle_info, attrs) do
def update_student_cycle_info(%StudentCycleInfo{} = student_cycle_info, attrs, opts \\ []) do
student_cycle_info
|> StudentCycleInfo.changeset(attrs)
|> Repo.update()
|> StudentsCycleInfoLog.maybe_create_student_cycle_info_log("UPDATE", opts)
end

@doc """
Deletes a student_cycle_info.
## Options:
- `:log_profile_id` - logs the operation, linked to given profile
## Examples
iex> delete_student_cycle_info(student_cycle_info)
Expand All @@ -115,8 +130,9 @@ defmodule Lanttern.StudentsCycleInfo do
{:error, %Ecto.Changeset{}}
"""
def delete_student_cycle_info(%StudentCycleInfo{} = student_cycle_info) do
def delete_student_cycle_info(%StudentCycleInfo{} = student_cycle_info, opts \\ []) do
Repo.delete(student_cycle_info)
|> StudentsCycleInfoLog.maybe_create_student_cycle_info_log("DELETE", opts)
end

@doc """
Expand Down
81 changes: 81 additions & 0 deletions lib/lanttern/students_cycle_info_log.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
defmodule Lanttern.StudentsCycleInfoLog do
@moduledoc """
The StudentsCycleInfoLog context.
"""

import Ecto.Query, warn: false
alias Lanttern.Repo

alias Lanttern.StudentsCycleInfo.StudentCycleInfo
alias Lanttern.StudentsCycleInfoLog.StudentCycleInfoLog

@doc """
Creates a student_cycle_info_log.
## Examples
iex> create_student_cycle_info_log(%{field: value})
{:ok, %StudentCycleInfoLog{}}
iex> create_student_cycle_info_log(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_student_cycle_info_log(attrs \\ %{}) do
%StudentCycleInfoLog{}
|> StudentCycleInfoLog.changeset(attrs)
|> Repo.insert()
end

@doc """
Util for create a student cycle info log.
Accepts `{:ok, %StudentCycleInfo{}}` or `{:error, %Ecto.Changeset{}}` tuple as first arg.
Always returns the note or tuple as is. The logging process is handled in an async task.
### Options:
- `:log_profile_id` – the profile id used to log the operation. if not present, logging will be skipped
"""
@spec maybe_create_student_cycle_info_log(
{:ok, StudentCycleInfo.t()} | {:error, Ecto.Changeset.t()},
operation :: String.t(),
opts :: Keyword.t()
) ::
{:ok, StudentCycleInfo.t()} | {:error, Ecto.Changeset.t()}
def maybe_create_student_cycle_info_log(operation_tuple, operation, opts \\ [])

def maybe_create_student_cycle_info_log({:error, _} = operation_tuple, _, _),
do: operation_tuple

def maybe_create_student_cycle_info_log(
{:ok, %StudentCycleInfo{} = student_cycle_info} = operation_tuple,
operation,
opts
) do
case Keyword.get(opts, :log_profile_id) do
profile_id when not is_nil(profile_id) ->
do_create_student_cycle_info_log(student_cycle_info, operation, profile_id)
operation_tuple

_ ->
operation_tuple
end
end

defp do_create_student_cycle_info_log(student_cycle_info, operation, profile_id) do
attrs =
student_cycle_info
|> Map.from_struct()
|> Map.put(:student_cycle_info_id, student_cycle_info.id)
|> Map.put(:profile_id, profile_id)
|> Map.put(:operation, operation)

# create the log in a async task (fire and forget)
Task.Supervisor.start_child(Lanttern.TaskSupervisor, fn ->
create_student_cycle_info_log(attrs)
end)
end
end
48 changes: 48 additions & 0 deletions lib/lanttern/students_cycle_info_log/student_cycle_info_log.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
defmodule Lanttern.StudentsCycleInfoLog.StudentCycleInfoLog do
@moduledoc """
The `StudentCycleInfoLog` schema
"""

use Ecto.Schema
import Ecto.Changeset

@schema_prefix "log"
schema "students_cycle_info" do
field :student_cycle_info_id, :id
field :profile_id, :id
field :operation, :string

field :student_id, :id
field :cycle_id, :id
field :school_id, :id
field :school_info, :string
field :family_info, :string
field :profile_picture_url, :string

timestamps(updated_at: false)
end

@doc false
def changeset(student_cycle_info_log, attrs) do
student_cycle_info_log
|> cast(attrs, [
:student_cycle_info_id,
:profile_id,
:operation,
:student_id,
:cycle_id,
:school_id,
:school_info,
:family_info,
:profile_picture_url
])
|> validate_required([
:student_cycle_info_id,
:profile_id,
:operation,
:student_id,
:cycle_id,
:school_id
])
end
end
2 changes: 1 addition & 1 deletion lib/lanttern_web/components/form_components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ defmodule LantternWeb.FormComponents do
<div class="flex items-center gap-2">
<%= render_slot(@actions_left) %>
</div>
<div class="flex items-center gap-2">
<div class="flex items-center gap-4">
<%= render_slot(@actions) %>
</div>
</div>
Expand Down
15 changes: 10 additions & 5 deletions lib/lanttern_web/live/pages/school/students/id/about_component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ defmodule LantternWeb.StudentLive.AboutComponent do
student_cycle_info={@student_cycle_info}
type="school"
label={gettext("Add school area student info...")}
current_profile_id={@current_user.current_profile_id}
notify_component={@myself}
/>
<% else %>
Expand Down Expand Up @@ -108,6 +109,7 @@ defmodule LantternWeb.StudentLive.AboutComponent do
student_cycle_info={@student_cycle_info}
type="family"
label={gettext("Add family area student info...")}
current_profile_id={@current_user.current_profile_id}
notify_component={@myself}
/>
<% else %>
Expand Down Expand Up @@ -216,11 +218,14 @@ defmodule LantternWeb.StudentLive.AboutComponent do
nil ->
# create student cycle info if it does not exist
{:ok, info} =
StudentsCycleInfo.create_student_cycle_info(%{
school_id: socket.assigns.student.school_id,
student_id: socket.assigns.student.id,
cycle_id: socket.assigns.current_cycle.id
})
StudentsCycleInfo.create_student_cycle_info(
%{
school_id: socket.assigns.student.school_id,
student_id: socket.assigns.student.id,
cycle_id: socket.assigns.current_cycle.id
},
log_profile_id: socket.assigns.current_user.current_profile_id
)

info

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ defmodule LantternWeb.StudentsCycleInfo.StudentCycleInfoFormComponent do
- `:student_cycle_info` - `%StudentCycleInfo{}`
- `:type` - "school" or "family"
- `:current_user` - `%User{}` in `socket.assigns.current_user`
- `:current_profile_id` - in `socket.assigns.current_user.current_profile_id`
### Optional attrs
- `:class`
- `:allow_editing` - Defaults to `false`
"""

Expand All @@ -24,7 +23,7 @@ defmodule LantternWeb.StudentsCycleInfo.StudentCycleInfoFormComponent do
def render(assigns) do
~H"""
<div class={@class}>
<.form for={@form} phx-submit="save" phx-target={@myself} id="note-form">
<.form for={@form} phx-submit="save" phx-target={@myself} id={@id}>
<.textarea_with_actions
id={@field.id}
name={@field.name}
Expand All @@ -37,10 +36,10 @@ defmodule LantternWeb.StudentsCycleInfo.StudentCycleInfoFormComponent do
<.markdown_supported />
</:actions_left>
<:actions>
<.action type="button" theme="subtle" phx-click="cancel" phx-target={@myself}>
<.action type="button" theme="subtle" size="md" phx-click="cancel" phx-target={@myself}>
<%= gettext("Cancel") %>
</.action>
<.action type="submit" theme="primary">
<.action type="submit" theme="primary" size="md" icon_name="hero-check">
<%= gettext("Save") %>
</.action>
</:actions>
Expand Down Expand Up @@ -125,14 +124,18 @@ defmodule LantternWeb.StudentsCycleInfo.StudentCycleInfoFormComponent do

# helpers

defp save_info(
%{assigns: %{student_cycle_info: %StudentCycleInfo{} = student_cycle_info}} = _socket,
params
) do
defp save_info(socket, params) do
%{
assigns: %{
student_cycle_info: %StudentCycleInfo{} = student_cycle_info,
current_profile_id: current_profile_id
}
} = socket

StudentsCycleInfo.update_student_cycle_info(
student_cycle_info,
params
# log_operation: true
params,
log_profile_id: current_profile_id
)
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@ defmodule Lanttern.Repo.Migrations.CreateStudentsCycleInfo do
add :profile_picture_url, :text

add :student_id, references(:students, with: [school_id: :school_id], on_delete: :nothing),
# null constraint fixed in Lanttern.Repo.Migrations.FixStudentsCycleInfoNullConstraints
required: true

add :cycle_id,
references(:school_cycles, with: [school_id: :school_id], on_delete: :nothing),
# null constraint fixed in Lanttern.Repo.Migrations.FixStudentsCycleInfoNullConstraints
required: true

add :school_id, references(:schools, on_delete: :nothing), required: true
add :school_id, references(:schools, on_delete: :nothing),
# null constraint fixed in Lanttern.Repo.Migrations.FixStudentsCycleInfoNullConstraints
required: true

timestamps()
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
defmodule Lanttern.Repo.Migrations.CreateStudentsCycleInfoLogs do
use Ecto.Migration

@prefix "log"

def change do
create table(:students_cycle_info, prefix: @prefix) do
add :student_cycle_info_id, :bigint, null: false
add :profile_id, :bigint, null: false
add :operation, :text, null: false

add :student_id, :bigint, null: false
add :cycle_id, :bigint, null: false
add :school_id, :bigint, null: false

add :school_info, :text
add :family_info, :text
add :profile_picture_url, :text

timestamps(updated_at: false)
end

create constraint(
:students_cycle_info,
:valid_operations,
prefix: @prefix,
check: "operation IN ('CREATE', 'UPDATE', 'DELETE')"
)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
defmodule Lanttern.Repo.Migrations.FixStudentsCycleInfoNullConstraints do
use Ecto.Migration

def change do
execute "ALTER TABLE students_cycle_info ALTER COLUMN student_id SET NOT NULL",
"ALTER TABLE students_cycle_info ALTER COLUMN student_id DROP NOT NULL"

execute "ALTER TABLE students_cycle_info ALTER COLUMN cycle_id SET NOT NULL",
"ALTER TABLE students_cycle_info ALTER COLUMN cycle_id DROP NOT NULL"

execute "ALTER TABLE students_cycle_info ALTER COLUMN school_id SET NOT NULL",
"ALTER TABLE students_cycle_info ALTER COLUMN school_id DROP NOT NULL"
end
end
Loading

0 comments on commit afea763

Please sign in to comment.