diff --git a/lib/philomena/site_notices.ex b/lib/philomena/site_notices.ex index dcd8b04b..1a9bb5ce 100644 --- a/lib/philomena/site_notices.ex +++ b/lib/philomena/site_notices.ex @@ -54,9 +54,9 @@ defmodule Philomena.SiteNotices do {:error, %Ecto.Changeset{}} """ - def create_site_notice(attrs \\ %{}) do - %SiteNotice{} - |> SiteNotice.changeset(attrs) + def create_site_notice(creator, attrs \\ %{}) do + %SiteNotice{user_id: creator.id} + |> SiteNotice.save_changeset(attrs) |> Repo.insert() end @@ -74,7 +74,7 @@ defmodule Philomena.SiteNotices do """ def update_site_notice(%SiteNotice{} = site_notice, attrs) do site_notice - |> SiteNotice.changeset(attrs) + |> SiteNotice.save_changeset(attrs) |> Repo.update() end diff --git a/lib/philomena/site_notices/site_notice.ex b/lib/philomena/site_notices/site_notice.ex index 5888fbdc..0da35f06 100644 --- a/lib/philomena/site_notices/site_notice.ex +++ b/lib/philomena/site_notices/site_notice.ex @@ -3,17 +3,21 @@ defmodule Philomena.SiteNotices.SiteNotice do import Ecto.Changeset alias Philomena.Users.User + import Philomena.Schema.Time schema "site_notices" do belongs_to :user, User field :title, :string - field :text, :string - field :link, :string - field :link_text, :string - field :live, :boolean, default: false - field :start_date, :naive_datetime - field :finish_date, :naive_datetime + field :text, :string, default: "" + field :link, :string, default: "" + field :link_text, :string, default: "" + field :live, :boolean, default: true + field :start_date, :utc_datetime + field :finish_date, :utc_datetime + + field :start_time, :string, virtual: true + field :finish_time, :string, virtual: true timestamps(inserted_at: :created_at) end @@ -22,6 +26,15 @@ defmodule Philomena.SiteNotices.SiteNotice do def changeset(site_notice, attrs) do site_notice |> cast(attrs, []) + |> propagate_time(:start_date, :start_time) + |> propagate_time(:finish_date, :finish_time) |> validate_required([]) end + + def save_changeset(site_notice, attrs) do + site_notice + |> cast(attrs, [:title, :text, :link, :link_text, :live, :start_time, :finish_time]) + |> assign_time(:start_time, :start_date) + |> assign_time(:finish_time, :finish_date) + end end diff --git a/lib/philomena_web/controllers/admin/site_notice_controller.ex b/lib/philomena_web/controllers/admin/site_notice_controller.ex new file mode 100644 index 00000000..0839dbfb --- /dev/null +++ b/lib/philomena_web/controllers/admin/site_notice_controller.ex @@ -0,0 +1,69 @@ +defmodule PhilomenaWeb.Admin.SiteNoticeController do + use PhilomenaWeb, :controller + + alias Philomena.SiteNotices.SiteNotice + alias Philomena.SiteNotices + alias Philomena.Repo + import Ecto.Query + + plug :verify_authorized + plug :load_and_authorize_resource, model: SiteNotice, except: [:index] + + def index(conn, _params) do + site_notices = + SiteNotice + |> order_by(desc: :start_date) + |> Repo.paginate(conn.assigns.scrivener) + + render(conn, "index.html", site_notices: site_notices) + end + + def new(conn, _params) do + changeset = SiteNotices.change_site_notice(%SiteNotice{}) + render(conn, "new.html", changeset: changeset) + end + + def create(conn, %{"site_notice" => site_notice_params}) do + case SiteNotices.create_site_notice(conn.assigns.current_user, site_notice_params) do + {:ok, _site_notice} -> + conn + |> put_flash(:info, "Successfully created site notice.") + |> redirect(to: Routes.admin_site_notice_path(conn, :index)) + + {:error, changeset} -> + render(conn, "new.html", changeset: changeset) + end + end + + def edit(conn, _params) do + changeset = SiteNotices.change_site_notice(conn.assigns.site_notice) + render(conn, "edit.html", changeset: changeset) + end + + def update(conn, %{"site_notice" => site_notice_params}) do + case SiteNotices.update_site_notice(conn.assigns.site_notice, site_notice_params) do + {:ok, _site_notice} -> + conn + |> put_flash(:info, "Succesfully updated site notice.") + |> redirect(to: Routes.admin_site_notice_path(conn, :index)) + + {:error, changeset} -> + render(conn, "edit.html", changeset: changeset) + end + end + + def delete(conn, _params) do + {:ok, _site_notice} = SiteNotices.delete_site_notice(conn.assigns.site_notice) + + conn + |> put_flash(:info, "Sucessfully deleted site notice.") + |> redirect(to: Routes.admin_site_notice_path(conn, :index)) + end + + defp verify_authorized(conn, _opts) do + case Canada.Can.can?(conn.assigns.current_user, :index, SiteNotice) do + true -> conn + false -> PhilomenaWeb.NotAuthorizedPlug.call(conn) + end + end +end diff --git a/lib/philomena_web/router.ex b/lib/philomena_web/router.ex index ca7918d4..16d25811 100644 --- a/lib/philomena_web/router.ex +++ b/lib/philomena_web/router.ex @@ -194,6 +194,8 @@ defmodule PhilomenaWeb.Router do resources "/user_bans", UserBanController, only: [:index, :new, :create, :edit, :update, :delete] resources "/subnet_bans", SubnetBanController, only: [:index, :new, :create, :edit, :update, :delete] resources "/fingerprint_bans", FingerprintBanController, only: [:index, :new, :create, :edit, :update, :delete] + + resources "/site_notices", SiteNoticeController, except: [:show] end resources "/duplicate_reports", DuplicateReportController, only: [] do diff --git a/lib/philomena_web/templates/admin/site_notice/_form.html.slime b/lib/philomena_web/templates/admin/site_notice/_form.html.slime new file mode 100644 index 00000000..2e614917 --- /dev/null +++ b/lib/philomena_web/templates/admin/site_notice/_form.html.slime @@ -0,0 +1,47 @@ += form_for @changeset, @action, fn f -> + = if @changeset.action do + .alert.alert-danger + p Oops, something went wrong! Please check the errors below. + + .field + => label f, :title, "Title (the bold bit) for the site notice; keep this short:" + = text_input f, :title, class: "input input--wide", placeholder: "Title", required: true + = error_tag f, :title + + .field + => label f, :text, "Main body of the site notice:" + = text_input f, :text, class: "input input--wide", placeholder: "Text", required: true + = error_tag f, :text + + h3 + ' Link + small + ' (optional; leave these two fields blank for no link) + + .field + => label f, :link_text, "Text which will contain the link:" + = text_input f, :link_text, class: "input input--wide", placeholder: "Link text" + = error_tag f, :link_text + + .field + => label f, :link, "Link which the site notice should take users to:" + = text_input f, :link, class: "input input--wide", placeholder: "Link" + = error_tag f, :link + + h3 Run Time + .field + => label f, :start_time, "Start time for the site notice (usually \"now\"):" + = text_input f, :start_time, class: "input input--wide", required: true + = error_tag f, :start_time + + .field + => label f, :finish_time, "Finish time for the site notice (e.g. \"2 weeks from now\"):" + = text_input f, :finish_time, class: "input input--wide", required: true + = error_tag f, :finish_time + + h3 Enable + .field + => checkbox f, :live, class: "checkbox" + = label f, :live, "Live" + + = submit "Save Site Notice", class: "button" diff --git a/lib/philomena_web/templates/admin/site_notice/edit.html.slime b/lib/philomena_web/templates/admin/site_notice/edit.html.slime new file mode 100644 index 00000000..bd745654 --- /dev/null +++ b/lib/philomena_web/templates/admin/site_notice/edit.html.slime @@ -0,0 +1,2 @@ +h1 Editing site notice += render PhilomenaWeb.Admin.SiteNoticeView, "_form.html", changeset: @changeset, action: Routes.admin_site_notice_path(@conn, :update, @site_notice), conn: @conn diff --git a/lib/philomena_web/templates/admin/site_notice/index.html.slime b/lib/philomena_web/templates/admin/site_notice/index.html.slime new file mode 100644 index 00000000..1ad8a692 --- /dev/null +++ b/lib/philomena_web/templates/admin/site_notice/index.html.slime @@ -0,0 +1,44 @@ +h1 Site Notices + +- route = fn p -> Routes.admin_site_notice_path(@conn, :index, p) end +- pagination = render PhilomenaWeb.PaginationView, "_pagination.html", page: @site_notices, route: route, conn: @conn + +.block + .block__header + a href=Routes.admin_site_notice_path(@conn, :new) + i.fa.fa-plus> + ' New site notice + + = pagination + + .block__content + table.table + thead + tr + th Title + th Start + th Finish + th Live? + th Options + tbody + = for site_notice <- @site_notices do + tr + td + em = site_notice.title + + td class=time_column_class(site_notice.start_date) + = pretty_time site_notice.start_date + + td class=time_column_class(site_notice.finish_date) + = pretty_time site_notice.finish_date + + td + = live_text site_notice + + td + => link "Edit", to: Routes.admin_site_notice_path(@conn, :edit, site_notice) + ' • + => link "Destroy", to: Routes.admin_site_notice_path(@conn, :delete, site_notice), data: [confirm: "Are you really, really sure?", method: "delete"] + + .block__header.block__header--light + = pagination diff --git a/lib/philomena_web/templates/admin/site_notice/new.html.slime b/lib/philomena_web/templates/admin/site_notice/new.html.slime new file mode 100644 index 00000000..b8c2f34b --- /dev/null +++ b/lib/philomena_web/templates/admin/site_notice/new.html.slime @@ -0,0 +1,2 @@ +h1 New site notice += render PhilomenaWeb.Admin.SiteNoticeView, "_form.html", changeset: @changeset, action: Routes.admin_site_notice_path(@conn, :create), conn: @conn diff --git a/lib/philomena_web/views/admin/site_notice_view.ex b/lib/philomena_web/views/admin/site_notice_view.ex new file mode 100644 index 00000000..114ffab1 --- /dev/null +++ b/lib/philomena_web/views/admin/site_notice_view.ex @@ -0,0 +1,15 @@ +defmodule PhilomenaWeb.Admin.SiteNoticeView do + use PhilomenaWeb, :view + + def time_column_class(time) do + now = DateTime.utc_now() + + case DateTime.diff(time, now) > 0 do + true -> "success" + false -> "danger" + end + end + + def live_text(%{live: true}), do: "Yes" + def live_text(_site_notice), do: "No" +end diff --git a/lib/relative_date/parser.ex b/lib/relative_date/parser.ex index 748f24c3..e6da0495 100644 --- a/lib/relative_date/parser.ex +++ b/lib/relative_date/parser.ex @@ -28,6 +28,13 @@ defmodule RelativeDate.Parser do |> eos() |> unwrap_and_tag(:moon) + now = + space + |> string("now") + |> concat(space) + |> eos() + |> unwrap_and_tag(:now) + date = space |> integer(min: 1) @@ -42,6 +49,7 @@ defmodule RelativeDate.Parser do relative_date = choice([ moon, + now, date ]) @@ -77,6 +85,9 @@ defmodule RelativeDate.Parser do {:ok, [moon: _moon], _1, _2, _3, _4} -> {:ok, DateTime.utc_now() |> DateTime.add(31_536_000_000, :second) |> DateTime.truncate(:second)} + {:ok, [now: _now], _1, _2, _3, _4} -> + {:ok, DateTime.utc_now() |> DateTime.truncate(:second)} + {:ok, [relative_date: [amount, scale, direction]], _1, _2, _3, _4} -> {:ok, DateTime.utc_now() |> DateTime.add(amount * scale * direction, :second) |> DateTime.truncate(:second)}