Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions config/dev.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@ port = System.get_env("PORT") || "7070"

config :mailgun_logger, MailgunLoggerWeb.Endpoint,
url: [
host: System.get_env("HOST", "0.0.0.0"),
scheme: "https",
host: System.get_env("HOST", "localhost"),
scheme: "http",
port: port
],
https: [
http: [
ip: {0, 0, 0, 0},
port: port,
cipher_suite: :strong,
keyfile: "priv/cert/selfsigned_key.pem",
certfile: "priv/cert/selfsigned.pem"
],
live_reload: [
web_console_logger: true,
Expand Down
52 changes: 27 additions & 25 deletions config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,34 @@ import Config
config :mailgun_logger,
store_messages: System.get_env("ML_STORE_MESSAGES", "false") |> String.downcase() == "true"

config :mailgun_logger, MailgunLoggerWeb.Endpoint,
server: true,
secret_key_base: System.get_env("SECRET_KEY_BASE")
if config_env() != :test do
config :mailgun_logger, MailgunLoggerWeb.Endpoint,
server: true,
secret_key_base: System.get_env("SECRET_KEY_BASE")

config :mailgun_logger, MailgunLogger.Repo,
username: System.get_env("ML_DB_USER"),
password: System.get_env("ML_DB_PASSWORD"),
database: System.get_env("ML_DB_NAME"),
hostname: System.get_env("ML_DB_HOST"),
port: System.get_env("ML_DB_PORT") || 5432
config :mailgun_logger, MailgunLogger.Repo,
username: System.get_env("ML_DB_USER"),
password: System.get_env("ML_DB_PASSWORD"),
database: System.get_env("ML_DB_NAME"),
hostname: System.get_env("ML_DB_HOST"),
port: System.get_env("ML_DB_PORT") || 5432

config :mailgun_logger, MailgunLogger.Mailer,
adapter: Bamboo.MailgunAdapter,
api_key: System.get_env("MAILGUN_API_KEY"),
domain: System.get_env("MAILGUN_DOMAIN"),
from: System.get_env("MAILGUN_FROM") || "no-reply@jackjoe.be"
config :mailgun_logger, MailgunLogger.Mailer,
adapter: Bamboo.MailgunAdapter,
api_key: System.get_env("MAILGUN_API_KEY"),
domain: System.get_env("MAILGUN_DOMAIN"),
from: System.get_env("MAILGUN_FROM") || "no-reply@jackjoe.be"

config :ex_aws,
access_key_id: System.get_env("AWS_ACCESS_KEY_ID"),
secret_access_key: System.get_env("AWS_SECRET_ACCESS_KEY"),
region: System.get_env("AWS_REGION"),
bucket: System.get_env("AWS_BUCKET"),
raw_path: System.get_env("RAW_PATH"),
s3: [
scheme: System.get_env("AWS_SCHEME"),
port: System.get_env("AWS_PORT"),
config :ex_aws,
access_key_id: System.get_env("AWS_ACCESS_KEY_ID"),
secret_access_key: System.get_env("AWS_SECRET_ACCESS_KEY"),
region: System.get_env("AWS_REGION"),
host: System.get_env("AWS_HOST")
]
bucket: System.get_env("AWS_BUCKET"),
raw_path: System.get_env("RAW_PATH"),
s3: [
scheme: System.get_env("AWS_SCHEME"),
port: System.get_env("AWS_PORT"),
region: System.get_env("AWS_REGION"),
host: System.get_env("AWS_HOST")
]
end
12 changes: 5 additions & 7 deletions config/test.exs
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import Config

# We don't run a server during test. If one is required,
# you can enable the server option below.
config :mailgun_logger, MailgunLoggerWeb.Endpoint,
http: [port: 4001],
server: false

# Quantum cron schedule
config :mailgun_logger, MailgunLogger.Scheduler,
jobs: []

config :logger, level: :warning
config :mailgun_logger, MailgunLogger.Repo, pool: Ecto.Adapters.SQL.Sandbox

config :mailgun_logger, MailgunLogger.Repo,
username: System.get_env("ML_DB_USER") || "travis",
username: System.get_env("ML_DB_USER") || "max",
password: System.get_env("ML_DB_PASSWORD") || "",
database: System.get_env("ML_DB_NAME") || "mailgun_logger_ci_test",
hostname: System.get_env("ML_DB_HOST") || "localhost"
database: System.get_env("ML_DB_NAME") || "mailgun_logger_test",
hostname: System.get_env("ML_DB_HOST") || "localhost",
port: String.to_integer(System.get_env("ML_DB_PORT") || "5432"),
pool: Ecto.Adapters.SQL.Sandbox
12 changes: 11 additions & 1 deletion lib/mailgun_logger/roles/roles.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ defmodule MailgunLogger.Roles do
alias MailgunLogger.User
alias MailgunLogger.Repo

@member_role "member"
@superuser_role "superuser"
@admin_role "admin"

#########################################################

@default_actions ~w()

@admin_actions ~w(do_stuff) ++ @default_actions
@member_actions ~w(view_events view_event_details edit_own_profile) ++ @default_actions

@admin_actions ~w(view_stats manage_accounts manage_users) ++ @member_actions

@superuser_actions ~w() ++ @admin_actions

Expand Down Expand Up @@ -55,6 +58,11 @@ defmodule MailgunLogger.Roles do
Enum.any?(roles, &can?(&1.name, action))
end

for action <- @member_actions do
action = String.to_atom(action)
def can?(@member_role, unquote(action)), do: true
end

for action <- @admin_actions do
action = String.to_atom(action)
def can?(@admin_role, unquote(action)), do: true
Expand All @@ -67,6 +75,7 @@ defmodule MailgunLogger.Roles do

def can?(_, _), do: false

def is?(%User{roles: roles}, :member), do: is(roles, "member")
def is?(%User{roles: roles}, :superuser), do: is(roles, "superuser")
def is?(%User{roles: roles}, :admin), do: is(roles, "admin")
def is?(_, _), do: raise("Roles.is/2 requires roles to be preloaded")
Expand All @@ -75,6 +84,7 @@ defmodule MailgunLogger.Roles do

def abilities(%User{roles: []}), do: []
def abilities(%User{roles: roles}), do: hd(roles) |> abilities()
def abilities(%Role{name: "member"}), do: @member_actions
def abilities(%Role{name: "admin"}), do: @admin_actions
def abilities(%Role{name: "superuser"}), do: @superuser_actions

Expand Down
6 changes: 5 additions & 1 deletion lib/mailgun_logger/seeder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ defmodule MailgunLogger.Seeder do

# alias MailgunLogger.UserRole

@roles [%Role{name: "superuser"}, %Role{name: "admin"}]
@roles [
%Role{name: "superuser"},
%Role{name: "admin"},
%Role{name: "member"}
]

def run do
Enum.each(@roles, &insert_if_new(&1))
Expand Down
40 changes: 39 additions & 1 deletion lib/mailgun_logger/users/users.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule MailgunLogger.Users do

alias MailgunLogger.Repo
alias MailgunLogger.User

alias MailgunLogger.Roles

@type ecto_user() :: {:ok, User.t()} | {:error, Ecto.Changeset.t()}
@type maybe_user() :: User.t() | nil
Expand Down Expand Up @@ -146,18 +146,56 @@ defmodule MailgunLogger.Users do

@spec create_user(map) :: ecto_user()
def create_user(params) do
roles = get_roles_from_params(params)

%User{}
|> User.changeset(params)
|> Ecto.Changeset.put_assoc(:roles, roles)
|> Repo.insert()
end

@spec update_user(User.t(), map) :: ecto_user()
def update_user(user, params) do
roles = get_roles_from_params(params)

user
|> User.update_changeset(params)
|> Ecto.Changeset.put_assoc(:roles, roles)
|> Repo.update()
end

@spec update_user(User.t(), User.t(), map) :: ecto_user()
def update_user(actor, user, params) do
roles = get_roles_from_params(params)
changeset = User.update_changeset(user, params)

if self_downgrade?(actor, user, roles) do
changeset
|> Ecto.Changeset.add_error(:roles, "You cannot remove your own user management access.")
|> then(&{:error, &1})
else
changeset
|> Ecto.Changeset.put_assoc(:roles, roles)
|> Repo.update()
end
end

defp self_downgrade?(actor, user, roles) do
actor.id == user.id and not keeps_user_management_access?(roles)
end

defp keeps_user_management_access?(roles) do
Enum.any?(roles, &Roles.can?(&1.name, :manage_users))
end

defp get_roles_from_params(params) do
params
|> Map.get("role_ids", [])
|> Enum.reject(&(&1 in [nil, ""]))
|> Enum.map(&String.to_integer/1)
|> Roles.get_roles_by_id()
end

@spec delete_user(User.t()) :: ecto_user()
def delete_user(%User{} = user) do
Repo.delete(user)
Expand Down
2 changes: 1 addition & 1 deletion lib/mailgun_logger_web/controllers/profile_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ defmodule MailgunLoggerWeb.ProfileController do

def edit(conn, _) do
user = conn.assigns.current_user
changeset = User.changeset(user)
changeset = User.update_changeset(user)

conn
|> put_view(MailgunLoggerWeb.UserView)
Expand Down
23 changes: 16 additions & 7 deletions lib/mailgun_logger_web/controllers/user_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ defmodule MailgunLoggerWeb.UserController do

alias MailgunLogger.Users
alias MailgunLogger.User
alias MailgunLogger.Roles

def index(conn, _) do
users = Users.list_users()
Expand All @@ -11,31 +12,39 @@ defmodule MailgunLoggerWeb.UserController do

def new(conn, _) do
changeset = User.changeset(%User{})
render(conn, :new, changeset: changeset)
roles = Roles.list_roles()
render(conn, :new, changeset: changeset, roles: roles)
end

def create(conn, %{"user" => params}) do
case Users.create_user(params) do
{:ok, _} -> redirect(conn, to: Routes.user_path(conn, :index))
{:error, changeset} -> render(conn, :new, changeset: changeset)
{:ok, _} ->
redirect(conn, to: Routes.user_path(conn, :index))

{:error, changeset} ->
roles = Roles.list_roles()
render(conn, :new, changeset: changeset, roles: roles)
end
end

def edit(conn, %{"id" => id}) do
user = Users.get_user!(id)
changeset = User.changeset(user)
render(conn, :edit, changeset: changeset, user: user)
changeset = User.update_changeset(user)
roles = Roles.list_roles()
render(conn, :edit, changeset: changeset, user: user, roles: roles)
end

def update(conn, %{"id" => id, "user" => params}) do
user = Users.get_user!(id)
current_user = conn.assigns.current_user

case Users.update_user(user, params) do
case Users.update_user(current_user, user, params) do
{:ok, _} ->
redirect(conn, to: Routes.user_path(conn, :index))

{:error, changeset} ->
render(conn, :edit, changeset: changeset, user: user)
roles = Roles.list_roles()
render(conn, :edit, changeset: changeset, user: user, roles: roles)
end
end

Expand Down
28 changes: 28 additions & 0 deletions lib/mailgun_logger_web/plugs/authorize.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
defmodule MailgunLoggerWeb.Plugs.Authorize do
import Plug.Conn
import Phoenix.Controller

alias MailgunLogger.Roles
alias MailgunLoggerWeb.Router.Helpers, as: Routes

@moduledoc """
Plug that checks whether the current user has the required permission.
"""

@spec init(atom()) :: atom()
def init(permission), do: permission

@spec call(Plug.Conn.t(), atom()) :: Plug.Conn.t()
def call(conn, permission) do
user = conn.assigns.current_user

if Roles.can?(user, permission) do
conn
else
conn
|> put_flash(:error, "You are not authorized to access this page.")
|> redirect(to: Routes.event_path(conn, :index))
|> halt()
end
end
end
6 changes: 5 additions & 1 deletion lib/mailgun_logger_web/plugs/setup_check.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
defmodule MailgunLoggerWeb.Plugs.SetupCheck do
import Plug.Conn
import Phoenix.Controller

alias MailgunLoggerWeb.Router.Helpers, as: Routes
Expand All @@ -15,7 +16,10 @@ defmodule MailgunLoggerWeb.Plugs.SetupCheck do
def call(conn, _) do
case Users.any_users?() do
true -> conn
false -> redirect(conn, to: Routes.setup_path(conn, :index))
false ->
conn
|> redirect(to: Routes.setup_path(conn, :index))
|> halt()
end
end
end
Loading