Commit aadbb7fc authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'rename-project-to-i_love_api' into 'master'

Rename project to ILoveApi

See merge request !2
parents 6bffcd33 e5caec70
# This file is a template, and might need editing before it works on your project.
# This template uses the non default language docker image
# The image already has Hex installed. You might want to consider to use `elixir:latest`
image: trenpixster/elixir:latest
.before_script_deploy: &before_script_deploy
before_script:
- >
: "${HEROKU_EMAIL:?Please set HEROKU_EMAIL in your CI/CD config vars}"
- >
: "${HEROKU_AUTH_TOKEN:?Please set HEROKU_AUTH_TOKEN in your CI/CD config vars}"
- curl https://cli-assets.heroku.com/install-standalone.sh | sh
- |
cat >~/.netrc <<EOF
machine api.heroku.com
login $HEROKU_EMAIL
password $HEROKU_AUTH_TOKEN
machine git.heroku.com
login $HEROKU_EMAIL
password $HEROKU_AUTH_TOKEN
EOF
- chmod 600 ~/.netrc
- git config --global user.email "remy@rymai.me"
- git config --global user.name "Rémy Coutable"
test:
stage: test
# Pick zero or more services to be used on all builds.
# Only needed when using a docker container to run your tests in.
# Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-service
services:
- postgres:latest
before_script:
- mix deps.get
script:
- mix test
variables:
APPNAME_PRODUCTION: i-love
APPNAME_STAGING: i-love-staging
deploy_to_staging:
<<: *before_script_deploy
stage: deploy
environment:
name: staging
url: https://$APPNAME_STAGING.herokuapp.com/
script:
- git remote add staging https://git.heroku.com/$APPNAME_STAGING.git
- git push staging master
- heroku pg:backups:capture --app $APPNAME_PRODUCTION
- heroku pg:backups:restore `heroku pg:backups:url --app $APPNAME_PRODUCTION` --app $APPNAME_STAGING --confirm $APPNAME_STAGING
- heroku run mix exto.migrate --app $APPNAME_STAGING
when: manual
only:
- master
deploy_to_production:
stage: deploy
environment:
name: production
url: https://$APPNAME_PRODUCTION.herokuapp.com/
script:
- git remote add production https://git.heroku.com/$APPNAME_PRODUCTION.git
- git push production master
- heroku pg:backups:capture --app $APPNAME_PRODUCTION
- heroku run mix exto.migrate --app $APPNAME_PRODUCTION
when: manual
only:
- master
# ILoveBackend
# ILoveApi
To start your Phoenix server:
......
......@@ -6,18 +6,18 @@
use Mix.Config
# General application configuration
config :i_love_backend,
ecto_repos: [ILoveBackend.Repo]
config :i_love_api,
ecto_repos: [ILoveApi.Repo]
# Configures the endpoint
config :i_love_backend, ILoveBackendWeb.Endpoint,
config :i_love_api, ILoveApiWeb.Endpoint,
url: [host: "localhost"],
secret_key_base: "BsSzuYD4hw+cvO9s5ZosMB4G1k0/oI22ZdKwcd+GKq97AYRFeZk3ZEa2/Mhaj0aC",
render_errors: [view: ILoveBackendWeb.ErrorView, accepts: ~w(html json)],
pubsub: [name: ILoveBackend.PubSub,
render_errors: [view: ILoveApiWeb.ErrorView, accepts: ~w(html json)],
pubsub: [name: ILoveApi.PubSub,
adapter: Phoenix.PubSub.PG2]
config :i_love_backend, admin_basic_auth: [
config :i_love_api, admin_basic_auth: [
username: "admin",
password: "admin",
realm: "Admin Area"
......
......@@ -6,7 +6,7 @@ use Mix.Config
# The watchers configuration can be used to run external
# watchers to your application. For example, we use it
# with brunch.io to recompile .js and .css sources.
config :i_love_backend, ILoveBackendWeb.Endpoint,
config :i_love_api, ILoveApiWeb.Endpoint,
http: [port: 4000],
debug_errors: true,
code_reloader: true,
......@@ -31,13 +31,13 @@ config :i_love_backend, ILoveBackendWeb.Endpoint,
# different ports.
# Watch static and templates for browser reloading.
config :i_love_backend, ILoveBackendWeb.Endpoint,
config :i_love_api, ILoveApiWeb.Endpoint,
live_reload: [
patterns: [
~r{priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$},
~r{priv/gettext/.*(po)$},
~r{lib/i_love_backend_web/views/.*(ex)$},
~r{lib/i_love_backend_web/templates/.*(eex)$}
~r{lib/i_love_api_web/views/.*(ex)$},
~r{lib/i_love_api_web/templates/.*(eex)$}
]
]
......@@ -49,7 +49,7 @@ config :logger, :console, format: "[$level] $message\n"
config :phoenix, :stacktrace_depth, 20
# Configure your database
config :i_love_backend, ILoveBackend.Repo,
config :i_love_api, ILoveApi.Repo,
adapter: Ecto.Adapters.Postgres,
url: "postgres://postgres:postgres@localhost/i_love_backend_dev",
url: "postgres://postgres:postgres@localhost/i_love_api_dev",
pool_size: 10
......@@ -3,7 +3,7 @@ use Mix.Config
# For production, we often load configuration from external
# sources, such as your system environment. For this reason,
# you won't find the :http configuration below, but set inside
# ILoveBackendWeb.Endpoint.init/2 when load_from_system_env is
# ILoveApiWeb.Endpoint.init/2 when load_from_system_env is
# true. Any dynamic configuration should be done there.
#
# Don't forget to configure the url host to something meaningful,
......@@ -13,7 +13,7 @@ use Mix.Config
# containing the digested version of static files. This
# manifest is generated by the mix phx.digest task
# which you typically run after static files are built.
config :i_love_backend, ILoveBackendWeb.Endpoint,
config :i_love_api, ILoveApiWeb.Endpoint,
load_from_system_env: true,
url: [scheme: "https", host: "i-love-api.herokuapp.com", port: 443],
force_ssl: [rewrite_on: [:x_forwarded_proto]],
......@@ -24,14 +24,14 @@ config :i_love_backend, ILoveBackendWeb.Endpoint,
config :logger, level: :info
# Configure your database
config :i_love_backend, ILoveBackend.Repo,
config :i_love_api, ILoveApi.Repo,
adapter: Ecto.Adapters.Postgres,
url: System.get_env("DATABASE_URL"),
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
ssl: true
# Admin area
config :i_love_backend, admin_basic_auth: [
config :i_love_api, admin_basic_auth: [
username: System.get_env("BASIC_AUTH_USERNAME") || "admin",
password: Map.fetch!(System.get_env(), "BASIC_AUTH_PASSWORD"),
realm: "Admin Area"
......@@ -42,7 +42,7 @@ config :i_love_backend, admin_basic_auth: [
# To get SSL working, you will need to add the `https` key
# to the previous section and set your `:url` port to 443:
#
# config :i_love_backend, ILoveBackendWeb.Endpoint,
# config :i_love_api, ILoveApiWeb.Endpoint,
# ...
# url: [host: "example.com", port: 443],
# https: [:inet6,
......@@ -57,7 +57,7 @@ config :i_love_backend, admin_basic_auth: [
# We also recommend setting `force_ssl`, ensuring no data is
# ever sent via http, always redirecting to https:
#
# config :i_love_backend, ILoveBackendWeb.Endpoint,
# config :i_love_api, ILoveApiWeb.Endpoint,
# force_ssl: [hsts: true]
#
# Check `Plug.SSL` for all available options in `force_ssl`.
......@@ -72,7 +72,7 @@ config :i_love_backend, admin_basic_auth: [
# Alternatively, you can configure exactly which server to
# start per endpoint:
#
# config :i_love_backend, ILoveBackendWeb.Endpoint, server: true
# config :i_love_api, ILoveApiWeb.Endpoint, server: true
#
# Finally import the config/prod.secret.exs
......
......@@ -2,7 +2,7 @@ use Mix.Config
# We don't run a server during test. If one is required,
# you can enable the server option below.
config :i_love_backend, ILoveBackendWeb.Endpoint,
config :i_love_api, ILoveApiWeb.Endpoint,
http: [port: 4001],
server: false
......@@ -10,10 +10,10 @@ config :i_love_backend, ILoveBackendWeb.Endpoint,
config :logger, level: :warn
# Configure your database
config :i_love_backend, ILoveBackend.Repo,
config :i_love_api, ILoveApi.Repo,
adapter: Ecto.Adapters.Postgres,
username: "postgres",
password: "postgres",
database: "i_love_backend_test",
hostname: "localhost",
database: "i_love_api_test",
hostname: if(System.get_env("CI"), do: "postgres", else: "localhost"),
pool: Ecto.Adapters.SQL.Sandbox
defmodule ILoveBackend do
defmodule ILoveApi do
@moduledoc """
ILoveBackend keeps the contexts that define your domain
ILoveApi keeps the contexts that define your domain
and business logic.
Contexts are also responsible for managing your data, regardless
......
defmodule ILoveBackend.Accounts do
defmodule ILoveApi.Accounts do
@moduledoc """
The Accounts context.
"""
import Ecto.Query, warn: false
alias ILoveBackend.Repo
alias ILoveApi.Repo
alias ILoveBackend.Accounts.User
alias ILoveApi.Accounts.User
alias ILoveApi.Devices
@doc """
Returns the list of users.
......@@ -19,7 +20,7 @@ defmodule ILoveBackend.Accounts do
"""
def list_users do
Repo.all(User)
|> Repo.preload(:scores)
|> Repo.preload([:device, :scores])
end
@doc """
......@@ -39,7 +40,7 @@ defmodule ILoveBackend.Accounts do
def get_user!(id) do
User
|> Repo.get!(id)
|> Repo.preload(:scores)
|> Repo.preload([:device, :scores])
end
@doc """
......@@ -56,15 +57,15 @@ defmodule ILoveBackend.Accounts do
** (Ecto.NoResultsError)
"""
def get_user!(id, uuid) do
user = User
|> Repo.get!(id)
|> Repo.preload(:scores)
if user.uuid == uuid do
user
else
{:error, :wrong_uuid}
def get_user(id, uuid) do
case Repo.get_by(User, id: id)
|> Repo.preload([:device, :scores]) do
nil -> {:error, :no_user}
%User{} = user ->
case user.uuid do
^uuid -> {:ok, user}
_ -> {:error, :wrong_uuid}
end
end
end
......@@ -81,11 +82,52 @@ defmodule ILoveBackend.Accounts do
"""
def create_user(attrs \\ %{}) do
%User{}
|> User.changeset(attrs)
change_user(attrs)
|> Repo.insert()
end
def get_or_create_user_by_username(_username = nil, _uuid) do
{:error, :no_username}
end
def get_or_create_user_by_username(_username, _uuid = nil) do
{:error, :no_uuid}
end
@doc """
Gets or creates a user.
## Examples
iex> get_or_create_user_by_username(username, uuid)
{:ok, %User{}}
iex> get_or_create_user_by_username(username, uuid)
{:error, :wrong_uuid}
iex> get_or_create_user_by_username(username, uuid)
{:error, %Ecto.Changeset{}}
"""
def get_or_create_user_by_username(username, uuid) do
case Repo.get_by(User, username: username) do
nil ->
{:ok, device} = Devices.get_or_create_device_by_uuid(uuid)
{:ok, user} = create_user(%{username: username, device_id: device.id})
user = Repo.get_by(User, id: user.id)
|> Repo.preload([:device, :scores])
{:ok, user}
user ->
user = Repo.preload(user, [:device, :scores])
if user.device.uuid == uuid do
{:ok, user}
else
{:error, :wrong_uuid}
end
end
end
@doc """
Updates a user.
......@@ -99,8 +141,7 @@ defmodule ILoveBackend.Accounts do
"""
def update_user(%User{} = user, attrs) do
user
|> User.changeset(attrs)
change_user(user, attrs)
|> Repo.update()
end
......@@ -123,13 +164,26 @@ defmodule ILoveBackend.Accounts do
@doc """
Returns an `%Ecto.Changeset{}` for tracking user changes.
## Examples
iex> change_user(%{username: "johndoe"})
%Ecto.Changeset{source: %User{}}
"""
def change_user(attrs) do
User.changeset(%User{}, attrs)
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking user changes.
## Examples
iex> change_user(user)
%Ecto.Changeset{source: %User{}}
"""
def change_user(%User{} = user) do
User.changeset(user, %{})
def change_user(%User{} = user, attrs) do
User.changeset(user, attrs)
end
end
defmodule ILoveBackend.Accounts.User do
defmodule ILoveApi.Accounts.User do
use Ecto.Schema
import Ecto.Changeset
alias ILoveBackend.Accounts.User
schema "users" do
field :username, :string
field :uuid, :string
has_many :scores, ILoveBackend.Scores.Score
belongs_to :device, ILoveApi.Devices.Device
has_many :scores, ILoveApi.Scores.Score
timestamps()
end
@doc false
def changeset(%User{} = user, attrs) do
def changeset(user, attrs) do
user
|> cast(attrs, [:uuid, :username])
|> validate_required([:uuid, :username])
|> cast(attrs, [:device_id, :username])
|> validate_required([:device_id, :username])
|> unique_constraint(:username)
end
end
defmodule ILoveBackend.Application do
defmodule ILoveApi.Application do
use Application
# See https://hexdocs.pm/elixir/Application.html
......@@ -9,23 +9,23 @@ defmodule ILoveBackend.Application do
# Define workers and child supervisors to be supervised
children = [
# Start the Ecto repository
supervisor(ILoveBackend.Repo, []),
supervisor(ILoveApi.Repo, []),
# Start the endpoint when the application starts
supervisor(ILoveBackendWeb.Endpoint, []),
# Start your own worker by calling: ILoveBackend.Worker.start_link(arg1, arg2, arg3)
# worker(ILoveBackend.Worker, [arg1, arg2, arg3]),
supervisor(ILoveApiWeb.Endpoint, []),
# Start your own worker by calling: ILoveApi.Worker.start_link(arg1, arg2, arg3)
# worker(ILoveApi.Worker, [arg1, arg2, arg3]),
]
# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: ILoveBackend.Supervisor]
opts = [strategy: :one_for_one, name: ILoveApi.Supervisor]
Supervisor.start_link(children, opts)
end
# Tell Phoenix to update the endpoint configuration
# whenever the application is updated.
def config_change(changed, _new, removed) do
ILoveBackendWeb.Endpoint.config_change(changed, removed)
ILoveApiWeb.Endpoint.config_change(changed, removed)
:ok
end
end
defmodule ILoveApi.Devices.Device do
use Ecto.Schema
import Ecto.Changeset
schema "devices" do
field :uuid, :string
has_one :user, ILoveApi.Accounts.User
has_many :scores, through: [:user, :scores]
timestamps()
end
@doc false
def changeset(user, attrs) do
user
|> cast(attrs, [:uuid])
|> validate_required([:uuid])
|> unique_constraint(:uuid)
end
end
defmodule ILoveApi.Devices do
@moduledoc """
The Scores context.
"""
import Ecto.Query, warn: false
alias ILoveApi.Repo
alias ILoveApi.Devices.Device
@doc """
Creates a device.
## Examples
iex> create_device(%{field: value})
{:ok, %User{}}
iex> create_device(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_device(attrs \\ %{}) do
%Device{}
|> Device.changeset(attrs)
|> Repo.insert()
end
@doc """
Gets or creates a device.
## Examples
iex> get_or_create_device_by_uuid(uuid)
{:ok, %Device{}}
iex> get_or_create_device_by_uuid(uuid)
{:error, %Ecto.Changeset{}}
"""
def get_or_create_device_by_uuid(uuid) do
case Repo.get_by(Device, uuid: uuid) do
nil -> create_device(%{uuid: uuid})
device -> {:ok, device}
end
end
end
defmodule ILoveApi.Repo do
use Ecto.Repo, otp_app: :i_love_api
end
defmodule ILoveBackend.Scores.Score do
defmodule ILoveApi.Scores.Score do
use Ecto.Schema
import Ecto.Changeset
alias ILoveBackend.Scores.Score
schema "scores" do
field :point, :integer
belongs_to :user, ILoveBackend.Accounts.User
belongs_to :user, ILoveApi.Accounts.User
has_one :device, through: [:user, :device_id]
timestamps()
end
@doc false
def changeset(%Score{} = score, attrs) do
def changeset(score, attrs) do
score
|> cast(attrs, [:point, :user_id])
|> validate_required([:point, :user_id])
|> cast(attrs, [:user_id, :point])
|> validate_required([:user_id, :point])
end
end
defmodule ILoveBackend.Scores do
defmodule ILoveApi.Scores do
@moduledoc """
The Scores context.
"""
import Ecto.Query, only: [from: 2]
alias ILoveBackend.Repo
alias ILoveApi.Repo
alias ILoveBackend.Scores.Score
alias ILoveBackend.Accounts
alias ILoveBackend.Accounts.User
alias ILoveApi.Scores.Score
alias ILoveApi.Accounts.User
@doc """
Returns the list of scores.
......@@ -24,7 +23,7 @@ defmodule ILoveBackend.Scores do
order_by: [desc: :point]
Repo.all(query)
|> Repo.preload(:user)
|> Repo.preload([user: [:device]])
end
@doc """
......@@ -44,7 +43,7 @@ defmodule ILoveBackend.Scores do
def get_score!(id) do
Score
|> Repo.get!(id)
|> Repo.preload(:user)
|> Repo.preload([user: [:device]])
end
@doc """
......@@ -60,9 +59,16 @@ defmodule ILoveBackend.Scores do
"""
def create_score(attrs \\ %{}) do
%Score{}
|> Score.changeset(attrs)
|> Repo.insert()
case %Score{}
|> Score.changeset(attrs)
|> Repo.insert() do
{:ok, score} ->
score = score
|> Repo.preload([user: [:device]])
{:ok, score}
any -> any
end
end
@doc """
......@@ -78,37 +84,14 @@ defmodule ILoveBackend.Scores do
"""
def create_score(%User{} = user, attrs) do
%Score{}
|> Score.changeset(attrs)
|> Ecto.Changeset.put_change(:user_id, user.id)
|> Repo.insert()
end
@doc """
Creates a score.
## Examples
iex> create_score(%User{}, %{field: value})
{:ok, %Score{}}
iex> create_score(%User{}, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def ensure_user_exists(%User{} = user) do
case Accounts.get_user!(user.id, user.uuid) do
{%User{} = user} ->
user
{:error, :wrong_uuid} ->
{:error, User.changeset(user)}
Ecto.NoResultsError ->
case Accounts.create_user(user) do
{:ok, user} ->
user
{:error, %Ecto.Changeset{} = changeset} ->
changeset
end
attrs = Map.merge(attrs, %{user_id: user.id})
case %Score{}
|> Score.changeset(attrs)
|> Repo.insert() do
{:ok, score} ->
{:ok, Repo.preload(score, [user: [:device]])}
any -> any
end
end
......
defmodule ILoveBackendWeb do
defmodule ILoveApiWeb do
@moduledoc """
The entrypoint for defining your web interface, such
as controllers, views, channels and so on.
This can be used in your application as:
use ILoveBackendWeb, :controller
use ILoveBackendWeb, :view
use ILoveApiWeb, :controller
use ILoveApiWeb, :view
The definitions below will be executed for every view,
controller, etc, so keep them short and clean, focused
......@@ -19,17 +19,17 @@ defmodule ILoveBackendWeb do
def controller do
quote do
use Phoenix.Controller, namespace: ILoveBackendWeb
use Phoenix.Controller, namespace: ILoveApiWeb
import Plug.Conn
import ILoveBackendWeb.Router.Helpers
import ILoveBackendWeb.Gettext
import ILoveApiWeb.Router.Helpers
import ILoveApiWeb.Gettext
end
end
def view do
quote do
use Phoenix.View, root: "lib/i_love_backend_web/templates",
namespace: ILoveBackendWeb
use Phoenix.View, root: "lib/i_love_api_web/templates",
namespace: ILoveApiWeb
# Import convenience functions from controllers
import Phoenix.Controller, only: [get_flash: 2, view_module: 1]
......@@ -37,9 +37,9 @@ defmodule ILoveBackendWeb do
# Use all HTML functionality (forms, tags, etc)
use Phoenix.HTML
import ILoveBackendWeb.Router.Helpers
import ILoveBackendWeb.ErrorHelpers
import ILoveBackendWeb.Gettext
import ILoveApiWeb.Router.Helpers
import ILoveApiWeb.ErrorHelpers
import ILoveApiWeb.Gettext