diff --git a/assets/css/pages/performance.scss b/assets/css/pages/performance.scss index 7da9384..b1851ab 100644 --- a/assets/css/pages/performance.scss +++ b/assets/css/pages/performance.scss @@ -1,9 +1,4 @@ -@media screen and (max-width: 600px) { - .workshops-br { - margin-bottom: 17px; - } -} - -#workshops { - text-align: left !important; +.workshop-paragraph { + text-align: center !important; + margin: 12px; } diff --git a/assets/css/shared.scss b/assets/css/shared.scss index 6ef2d15..cdbb572 100644 --- a/assets/css/shared.scss +++ b/assets/css/shared.scss @@ -40,3 +40,8 @@ section.logo ~ section.main { hr { width: inherit; } + +.foot-note { + margin-top: 20px; + margin-bottom: 20px; +} diff --git a/lib/runosaari/schedule.ex b/lib/runosaari/schedule.ex index 293f9a2..378dfda 100644 --- a/lib/runosaari/schedule.ex +++ b/lib/runosaari/schedule.ex @@ -114,4 +114,113 @@ defmodule Runosaari.Schedule do def change_performance(%Performance{} = performance, attrs \\ %{}) do Performance.changeset(performance, attrs) end + + alias Runosaari.Schedule.Workshop + + @doc """ + Returns the list of workshops. + + ## Examples + + iex> list_workshops() + [%Workshop{}, ...] + + """ + def list_workshops do + Repo.all(Workshop) + end + + @doc """ + Returns the list of workshops. + + ## Examples + + iex> list_workshops() + [%Workshop{}, ...] + + """ + def list_sorted_workshops do + Repo.all(Workshop |> order_by(:seqnum)) + end + + @doc """ + Gets a single workshop. + + Raises `Ecto.NoResultsError` if the Workshop does not exist. + + ## Examples + + iex> get_workshop!(123) + %Workshop{} + + iex> get_workshop!(456) + ** (Ecto.NoResultsError) + + """ + def get_workshop!(id), do: Repo.get!(Workshop, id) + + @doc """ + Creates a workshop. + + ## Examples + + iex> create_workshop(%{field: value}) + {:ok, %Workshop{}} + + iex> create_workshop(%{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def create_workshop(attrs \\ %{}) do + %Workshop{} + |> Workshop.changeset(attrs) + |> Repo.insert() + end + + @doc """ + Updates a workshop. + + ## Examples + + iex> update_workshop(workshop, %{field: new_value}) + {:ok, %Workshop{}} + + iex> update_workshop(workshop, %{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def update_workshop(%Workshop{} = workshop, attrs) do + workshop + |> Workshop.changeset(attrs) + |> Repo.update() + end + + @doc """ + Deletes a workshop. + + ## Examples + + iex> delete_workshop(workshop) + {:ok, %Workshop{}} + + iex> delete_workshop(workshop) + {:error, %Ecto.Changeset{}} + + """ + def delete_workshop(%Workshop{} = workshop) do + Repo.delete(workshop) + end + + @doc """ + Returns an `%Ecto.Changeset{}` for tracking workshop changes. + + ## Examples + + iex> change_workshop(workshop) + %Ecto.Changeset{data: %Workshop{}} + + """ + def change_workshop(%Workshop{} = workshop, attrs \\ %{}) do + Workshop.changeset(workshop, attrs) + end end diff --git a/lib/runosaari/schedule/workshop.ex b/lib/runosaari/schedule/workshop.ex new file mode 100644 index 0000000..4186f6b --- /dev/null +++ b/lib/runosaari/schedule/workshop.ex @@ -0,0 +1,19 @@ +defmodule Runosaari.Schedule.Workshop do + use Ecto.Schema + import Ecto.Changeset + + schema "workshops" do + field :name, :string + field :text, :string + field :seqnum, :integer + + timestamps() + end + + @doc false + def changeset(workshop, attrs) do + workshop + |> cast(attrs, [:name, :text, :seqnum]) + |> validate_required([:name, :text, :seqnum]) + end +end diff --git a/lib/runosaari_web/controllers/performance_controller.ex b/lib/runosaari_web/controllers/performance_controller.ex index 69f402f..2fce2d2 100644 --- a/lib/runosaari_web/controllers/performance_controller.ex +++ b/lib/runosaari_web/controllers/performance_controller.ex @@ -6,7 +6,9 @@ defmodule RunosaariWeb.PerformanceController do def index(conn, _params) do performances = Schedule.list_sorted_performances() - render(conn, "index.html", performances: performances) + workshops = Schedule.list_sorted_workshops() + + render(conn, "index.html", Map.new(performances: performances, workshops: workshops)) end def admin(conn, _params) do diff --git a/lib/runosaari_web/controllers/workshop_controller.ex b/lib/runosaari_web/controllers/workshop_controller.ex new file mode 100644 index 0000000..3af6d2e --- /dev/null +++ b/lib/runosaari_web/controllers/workshop_controller.ex @@ -0,0 +1,67 @@ +defmodule RunosaariWeb.WorkshopController do + use RunosaariWeb, :controller + + alias Runosaari.Schedule + alias Runosaari.Schedule.Workshop + + def index(conn, _params) do + workshops = Schedule.list_workshops() + render(conn, "index.html", workshops: workshops) + end + + def admin(conn, _params) do + workshops = Schedule.list_workshops() + render(conn, "admin.html", workshops: workshops) + end + + def new(conn, _params) do + changeset = Schedule.change_workshop(%Workshop{}) + render(conn, "new.html", changeset: changeset) + end + + def create(conn, %{"workshop" => workshop_params}) do + case Schedule.create_workshop(workshop_params) do + {:ok, workshop} -> + conn + |> put_flash(:info, "Workshop created successfully.") + |> redirect(to: Routes.admin_workshop_path(conn, :show, workshop)) + + {:error, %Ecto.Changeset{} = changeset} -> + render(conn, "new.html", changeset: changeset) + end + end + + def show(conn, %{"id" => id}) do + workshop = Schedule.get_workshop!(id) + render(conn, "show.html", workshop: workshop) + end + + def edit(conn, %{"id" => id}) do + workshop = Schedule.get_workshop!(id) + changeset = Schedule.change_workshop(workshop) + render(conn, "edit.html", workshop: workshop, changeset: changeset) + end + + def update(conn, %{"id" => id, "workshop" => workshop_params}) do + workshop = Schedule.get_workshop!(id) + + case Schedule.update_workshop(workshop, workshop_params) do + {:ok, workshop} -> + conn + |> put_flash(:info, "Workshop updated successfully.") + |> redirect(to: Routes.admin_workshop_path(conn, :show, workshop)) + + {:error, %Ecto.Changeset{} = changeset} -> + render(conn, "edit.html", workshop: workshop, changeset: changeset) + end + end + + def delete(conn, %{"id" => id}) do + workshop = Schedule.get_workshop!(id) + {:ok, _workshop} = Schedule.delete_workshop(workshop) + + conn + |> put_flash(:info, "Workshop deleted successfully.") + |> redirect(to: Routes.admin_workshop_path(conn, :admin)) + end +end diff --git a/lib/runosaari_web/router.ex b/lib/runosaari_web/router.ex index 4d1dde9..a6a1e1e 100644 --- a/lib/runosaari_web/router.ex +++ b/lib/runosaari_web/router.ex @@ -40,6 +40,8 @@ defmodule RunosaariWeb.Router do get "/info", InfoController, :admin resources "/survival", SurvivalController, except: [:index] get "/survival", SurvivalController, :admin + resources "/workshops", WorkshopController, except: [:index] + get "/workshops", WorkshopController, :admin end # Other scopes may use custom stacks. diff --git a/lib/runosaari_web/templates/performance/index.html.eex b/lib/runosaari_web/templates/performance/index.html.eex index 2a69272..3b95461 100644 --- a/lib/runosaari_web/templates/performance/index.html.eex +++ b/lib/runosaari_web/templates/performance/index.html.eex @@ -32,10 +32,10 @@ <% end %> <% end %>

Työpajat

-

- Jaana Kouri: Shamanistinen kirjoitustyöpaja
- Hanna Toivonen: Sarjakuvatyöpaja
-
- Näihin avataan ennakkoilmoittautuminen hyvissä ajoin. -

+ <%= for workshop <- @workshops do %> +

+ <%= workshop.name %><%= workshop.text %> +

+ <% end %> + Näihin avataan ennakkoilmoittautuminen hyvissä ajoin. diff --git a/lib/runosaari_web/templates/workshop/admin.html.eex b/lib/runosaari_web/templates/workshop/admin.html.eex new file mode 100644 index 0000000..824e784 --- /dev/null +++ b/lib/runosaari_web/templates/workshop/admin.html.eex @@ -0,0 +1,32 @@ +
+

HALLINTA - Työpajat

+ + + + + + + + + + + + + <%= for workshop <- @workshops do %> + + + + + + + + <% end %> + +
NimiTekstiPrioriteetti
<%= workshop.name %><%= workshop.text %><%= workshop.seqnum %> + <%= link "Lisätietoja", to: Routes.admin_workshop_path(@conn, :show, workshop) %> + <%= link "Muokkaa", to: Routes.admin_workshop_path(@conn, :edit, workshop) %> + <%= link "Poista", to: Routes.admin_workshop_path(@conn, :delete, workshop), method: :delete, data: [confirm: "Oletko varma?"] %> +
+ + <%= link "Luo uusi työpaja", to: Routes.admin_workshop_path(@conn, :new) %> +
diff --git a/lib/runosaari_web/templates/workshop/edit.html.eex b/lib/runosaari_web/templates/workshop/edit.html.eex new file mode 100644 index 0000000..931f168 --- /dev/null +++ b/lib/runosaari_web/templates/workshop/edit.html.eex @@ -0,0 +1,5 @@ +

Muokkaa työpajan tietoja

+ +<%= render "form.html", Map.put(assigns, :action, Routes.admin_workshop_path(@conn, :update, @workshop)) %> + +<%= link "Takaisin", to: Routes.admin_workshop_path(@conn, :admin) %> diff --git a/lib/runosaari_web/templates/workshop/form.html.eex b/lib/runosaari_web/templates/workshop/form.html.eex new file mode 100644 index 0000000..80e69a0 --- /dev/null +++ b/lib/runosaari_web/templates/workshop/form.html.eex @@ -0,0 +1,23 @@ +<%= form_for @changeset, @action, fn f -> %> + <%= if @changeset.action do %> +
+

Joku kentistä on tyhjä.

+
+ <% end %> + + <%= label f, :name, "Nimi" %> + <%= text_input f, :name %> + <%= error_tag f, :name %> + + <%= label f, :text, "Teksti" %> + <%= textarea f, :text %> + <%= error_tag f, :text %> + + <%= label f, :seqnum, "Prioriteetti (1 on korkein)" %> + <%= number_input f, :seqnum %> + <%= error_tag f, :seqnum %> + +
+ <%= submit "Tallenna" %> +
+<% end %> diff --git a/lib/runosaari_web/templates/workshop/new.html.eex b/lib/runosaari_web/templates/workshop/new.html.eex new file mode 100644 index 0000000..c93ba7b --- /dev/null +++ b/lib/runosaari_web/templates/workshop/new.html.eex @@ -0,0 +1,5 @@ +

Luo uusi työpaja

+ +<%= render "form.html", Map.put(assigns, :action, Routes.admin_workshop_path(@conn, :create)) %> + +<%= link "Takaisin", to: Routes.admin_workshop_path(@conn, :admin) %> diff --git a/lib/runosaari_web/templates/workshop/show.html.eex b/lib/runosaari_web/templates/workshop/show.html.eex new file mode 100644 index 0000000..c699ee4 --- /dev/null +++ b/lib/runosaari_web/templates/workshop/show.html.eex @@ -0,0 +1,23 @@ +

Työpajan tiedot

+ + + +<%= link "Muokkaa", to: Routes.admin_workshop_path(@conn, :edit, @workshop) %> +<%= link "Takaisin", to: Routes.admin_workshop_path(@conn, :admin) %> diff --git a/lib/runosaari_web/views/workshop_view.ex b/lib/runosaari_web/views/workshop_view.ex new file mode 100644 index 0000000..30d8b74 --- /dev/null +++ b/lib/runosaari_web/views/workshop_view.ex @@ -0,0 +1,3 @@ +defmodule RunosaariWeb.WorkshopView do + use RunosaariWeb, :view +end diff --git a/priv/repo/migrations/20210703152605_create_workshops.exs b/priv/repo/migrations/20210703152605_create_workshops.exs new file mode 100644 index 0000000..4ee3e7f --- /dev/null +++ b/priv/repo/migrations/20210703152605_create_workshops.exs @@ -0,0 +1,14 @@ +defmodule Runosaari.Repo.Migrations.CreateWorkshops do + use Ecto.Migration + + def change do + create table(:workshops) do + add :name, :string + add :text, :string, size: 2000 + add :seqnum, :integer + + timestamps() + end + + end +end diff --git a/test/runosaari/schedule_test.exs b/test/runosaari/schedule_test.exs index aea522c..a5dd85b 100644 --- a/test/runosaari/schedule_test.exs +++ b/test/runosaari/schedule_test.exs @@ -139,4 +139,65 @@ defmodule Runosaari.ScheduleTest do assert %Ecto.Changeset{} = Schedule.change_performance(performance) end end + + describe "workshops" do + alias Runosaari.Schedule.Workshop + + @valid_attrs %{name: "some name", text: "some text", seqnum: 42} + @update_attrs %{name: "some updated name", text: "some updated text", seqnum: 43} + @invalid_attrs %{seqnum: nil, text: nil} + + def workshop_fixture(attrs \\ %{}) do + {:ok, workshop} = + attrs + |> Enum.into(@valid_attrs) + |> Schedule.create_workshop() + + workshop + end + + test "list_workshops/0 returns all workshops" do + workshop = workshop_fixture() + assert Schedule.list_workshops() == [workshop] + end + + test "get_workshop!/1 returns the workshop with given id" do + workshop = workshop_fixture() + assert Schedule.get_workshop!(workshop.id) == workshop + end + + test "create_workshop/1 with valid data creates a workshop" do + assert {:ok, %Workshop{} = workshop} = Schedule.create_workshop(@valid_attrs) + assert workshop.seqnum == 42 + assert workshop.text == "some text" + end + + test "create_workshop/1 with invalid data returns error changeset" do + assert {:error, %Ecto.Changeset{}} = Schedule.create_workshop(@invalid_attrs) + end + + test "update_workshop/2 with valid data updates the workshop" do + workshop = workshop_fixture() + assert {:ok, %Workshop{} = workshop} = Schedule.update_workshop(workshop, @update_attrs) + assert workshop.seqnum == 43 + assert workshop.text == "some updated text" + end + + test "update_workshop/2 with invalid data returns error changeset" do + workshop = workshop_fixture() + assert {:error, %Ecto.Changeset{}} = Schedule.update_workshop(workshop, @invalid_attrs) + assert workshop == Schedule.get_workshop!(workshop.id) + end + + test "delete_workshop/1 deletes the workshop" do + workshop = workshop_fixture() + assert {:ok, %Workshop{}} = Schedule.delete_workshop(workshop) + assert_raise Ecto.NoResultsError, fn -> Schedule.get_workshop!(workshop.id) end + end + + test "change_workshop/1 returns a workshop changeset" do + workshop = workshop_fixture() + assert %Ecto.Changeset{} = Schedule.change_workshop(workshop) + end + end end diff --git a/test/runosaari_web/controllers/workshop_controller_test.exs b/test/runosaari_web/controllers/workshop_controller_test.exs new file mode 100644 index 0000000..15d86c5 --- /dev/null +++ b/test/runosaari_web/controllers/workshop_controller_test.exs @@ -0,0 +1,93 @@ +defmodule RunosaariWeb.WorkshopControllerTest do + use RunosaariWeb.ConnCase + + alias Runosaari.Schedule + + @create_attrs %{name: "some name", text: "some text", seqnum: 42} + @update_attrs %{name: "some updated name", text: "some updated text", seqnum: 43} + @invalid_attrs %{name: nil, text: nil, seqnum: nil} + + def fixture(:workshop) do + {:ok, workshop} = Schedule.create_workshop(@create_attrs) + workshop + end + + describe "admin" do + test "lists all workshops", %{conn: conn} do + conn = get(conn, Routes.admin_workshop_path(conn, :admin)) + assert html_response(conn, 200) =~ "HALLINTA - Työpajat" + end + end + + describe "new workshop" do + test "renders form", %{conn: conn} do + conn = get(conn, Routes.admin_workshop_path(conn, :new)) + assert html_response(conn, 200) =~ "Luo uusi työpaja" + end + end + + describe "create workshop" do + test "redirects to show when data is valid", %{conn: conn} do + conn = post(conn, Routes.admin_workshop_path(conn, :create), workshop: @create_attrs) + + assert %{id: id} = redirected_params(conn) + assert redirected_to(conn) == Routes.admin_workshop_path(conn, :show, id) + + conn = get(conn, Routes.admin_workshop_path(conn, :show, id)) + assert html_response(conn, 200) =~ "Työpajan tiedot" + end + + test "renders errors when data is invalid", %{conn: conn} do + conn = post(conn, Routes.admin_workshop_path(conn, :create), workshop: @invalid_attrs) + assert html_response(conn, 200) =~ "Luo uusi työpaja" + end + end + + describe "edit workshop" do + setup [:create_workshop] + + test "renders form for editing chosen workshop", %{conn: conn, workshop: workshop} do + conn = get(conn, Routes.admin_workshop_path(conn, :edit, workshop)) + assert html_response(conn, 200) =~ "Muokkaa työpajan tietoja" + end + end + + describe "update workshop" do + setup [:create_workshop] + + test "redirects when data is valid", %{conn: conn, workshop: workshop} do + conn = + put(conn, Routes.admin_workshop_path(conn, :update, workshop), workshop: @update_attrs) + + assert redirected_to(conn) == Routes.admin_workshop_path(conn, :show, workshop) + + conn = get(conn, Routes.admin_workshop_path(conn, :show, workshop)) + assert html_response(conn, 200) =~ "some updated text" + end + + test "renders errors when data is invalid", %{conn: conn, workshop: workshop} do + conn = + put(conn, Routes.admin_workshop_path(conn, :update, workshop), workshop: @invalid_attrs) + + assert html_response(conn, 200) =~ "Muokkaa työpajan tietoja" + end + end + + describe "delete workshop" do + setup [:create_workshop] + + test "deletes chosen workshop", %{conn: conn, workshop: workshop} do + conn = delete(conn, Routes.admin_workshop_path(conn, :delete, workshop)) + assert redirected_to(conn) == Routes.admin_workshop_path(conn, :admin) + + assert_error_sent 404, fn -> + get(conn, Routes.admin_workshop_path(conn, :show, workshop)) + end + end + end + + defp create_workshop(_) do + workshop = fixture(:workshop) + %{workshop: workshop} + end +end