Commit fc802789 authored by Mikko Ahlroth's avatar Mikko Ahlroth

Starting new user profile development

Getting user top languages and total XP works. Not checking private profile
yet
parent 763814fc
Pipeline #13849793 passed with stage
in 3 minutes and 1 second
defmodule CodeStats.Profile.PublicSchema do
use Absinthe.Schema
import Ecto.Query, only: [from: 2]
import_types(CodeStats.Profile.SchemaObjects)
query do
@desc "Get profile by username"
field :profile, :profile do
@desc "Username of profile"
arg(:username, type: :string)
resolve(fn %{username: username}, _ ->
# TODO: Check if profile is private and user is allowed access
get_user_data(username)
end)
end
end
defp get_user_data(username) do
query =
from(
u in CodeStats.User,
where: fragment("lower(?)", ^username) == fragment("lower(?)", u.username),
select: %{username: u.username, cache: u.cache, registered: u.inserted_at}
)
case CodeStats.Repo.one(query) do
nil -> {:error, "User not found"}
user -> {:ok, user}
end
end
end
defmodule CodeStats.Profile.SchemaObjects do
use Absinthe.Schema.Notation
use Absinthe.Ecto, repo: CodeStats.Repo
import Ecto.Query, only: [from: 2]
@desc "User profile public data"
object :profile do
field(:username, :string)
field(:registered, :datetime)
field :total_xp, :integer do
resolve(fn %{cache: cache}, _, _ ->
{:ok, get_cached_total(cache)}
end)
end
field :languages, list_of(:profile_language) do
resolve(fn %{cache: cache}, _, _ ->
{:ok, get_cached_languages(cache)}
end)
end
end
object :pulse do
field(:sent_at, :datetime)
field(:sent_at_local, :naive_datetime)
field(:tz_offset, :integer)
end
object :profile_language do
field(:name, :string)
field(:xp, :integer)
end
scalar :datetime, description: "RFC3339 time with timezone" do
serialize(&Calendar.DateTime.Format.rfc3339(&1))
end
scalar :naive_datetime, description: "ISO 8601 naive datetime" do
serialize(&Calendar.NaiveDateTime.Format.iso8601(&1))
end
defp get_cached_languages(%{"languages" => languages}) when is_map(languages) do
intkeys =
languages
|> Map.to_list()
|> Enum.map(fn {k, v} -> {String.to_integer(k), v} end)
|> Enum.into(%{})
ids = Map.keys(intkeys)
structs =
from(l in CodeStats.Language, where: l.id in ^ids, select: {l.id, l.name})
|> CodeStats.Repo.all()
|> Enum.into(%{})
Enum.map(ids, fn id -> %{name: structs[id], xp: intkeys[id]} end)
end
defp get_cached_total(%{"languages" => languages}) when is_map(languages) do
languages |> Map.values() |> Enum.reduce(0, fn acc, xp -> acc + xp end)
end
end
......@@ -2,93 +2,97 @@ defmodule CodeStatsWeb.Router do
use CodeStatsWeb, :router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug CodeStatsWeb.RememberMePlug
plug CodeStatsWeb.SetSessionUserPlug
plug(:accepts, ["html"])
plug(:fetch_session)
plug(:fetch_flash)
plug(:protect_from_forgery)
plug(:put_secure_browser_headers)
plug(CodeStatsWeb.RememberMePlug)
plug(CodeStatsWeb.SetSessionUserPlug)
end
pipeline :browser_auth do
plug CodeStatsWeb.AuthRequiredPlug
plug(CodeStatsWeb.AuthRequiredPlug)
end
pipeline :browser_unauth do
plug CodeStatsWeb.AuthNotAllowedPlug
plug(CodeStatsWeb.AuthNotAllowedPlug)
end
pipeline :api do
plug :accepts, ["json"]
plug(:accepts, ["json"])
end
pipeline :api_auth do
plug CodeStatsWeb.APIAuthRequiredPlug
plug(CodeStatsWeb.APIAuthRequiredPlug)
end
scope "/", CodeStatsWeb do
pipe_through :browser # Use the default browser stack
# Use the default browser stack
pipe_through(:browser)
get "/", PageController, :index
get("/", PageController, :index)
get "/api-docs", PageController, :api_docs
get "/tos", PageController, :terms
get "/plugins", PageController, :plugins
get "/changes", PageController, :changes
get("/api-docs", PageController, :api_docs)
get("/tos", PageController, :terms)
get("/plugins", PageController, :plugins)
get("/changes", PageController, :changes)
get "/aliases", AliasController, :list
get("/aliases", AliasController, :list)
get "/battle", BattleController, :battle
get("/battle", BattleController, :battle)
scope "/" do
pipe_through :browser_unauth
get "/login", AuthController, :render_login
post "/login", AuthController, :login
get "/signup", AuthController, :render_signup
post "/signup", AuthController, :signup
get "/forgot-password", AuthController, :render_forgot
post "/forgot-password", AuthController, :forgot
get "/reset-password/:token", AuthController, :render_reset
put "/reset-password/:token", AuthController, :reset
pipe_through(:browser_unauth)
get("/login", AuthController, :render_login)
post("/login", AuthController, :login)
get("/signup", AuthController, :render_signup)
post("/signup", AuthController, :signup)
get("/forgot-password", AuthController, :render_forgot)
post("/forgot-password", AuthController, :forgot)
get("/reset-password/:token", AuthController, :render_reset)
put("/reset-password/:token", AuthController, :reset)
end
get "/logout", AuthController, :logout
get("/logout", AuthController, :logout)
get "/users/:username", ProfileController, :profile
get("/users/:username", ProfileController, :profile)
scope "/my" do
pipe_through :browser_auth
pipe_through(:browser_auth)
get "/profile", ProfileController, :my_profile
get("/profile", ProfileController, :my_profile)
get "/preferences", PreferencesController, :edit
put "/preferences", PreferencesController, :do_edit
get("/preferences", PreferencesController, :edit)
put("/preferences", PreferencesController, :do_edit)
post "/password", PreferencesController, :change_password
post "/sound_of_inevitability", PreferencesController, :delete
post("/password", PreferencesController, :change_password)
post("/sound_of_inevitability", PreferencesController, :delete)
get "/machines", MachineController, :list
post "/machines", MachineController, :add
get "/machines/:id", MachineController, :view_single
put "/machines/:id", MachineController, :edit
delete "/machines/:id", MachineController, :delete
post "/machines/:id/activate", MachineController, :activate
post "/machines/:id/deactivate", MachineController, :deactivate
post "/machines/:id/key", MachineController, :regen_machine_key
get("/machines", MachineController, :list)
post("/machines", MachineController, :add)
get("/machines/:id", MachineController, :view_single)
put("/machines/:id", MachineController, :edit)
delete("/machines/:id", MachineController, :delete)
post("/machines/:id/activate", MachineController, :activate)
post("/machines/:id/deactivate", MachineController, :deactivate)
post("/machines/:id/key", MachineController, :regen_machine_key)
end
end
scope "/api", CodeStatsWeb do
pipe_through :api
scope "/api" do
pipe_through(:api)
get "/users/:username", ProfileController, :profile_api
get("/users/:username", CodeStatsWeb.ProfileController, :profile_api)
forward("/users-graph", Absinthe.Plug, schema: CodeStats.Profile.PublicSchema)
forward("/users-graphiql", Absinthe.Plug.GraphiQL, schema: CodeStats.Profile.PublicSchema)
scope "/my" do
pipe_through :api_auth
pipe_through(:api_auth)
post "/pulses", PulseController, :add
post("/pulses", CodeStatsWeb.PulseController, :add)
end
end
end
......@@ -2,15 +2,17 @@ defmodule CodeStats.Mixfile do
use Mix.Project
def project do
[app: :code_stats,
version: "2.0.0-wip",
elixir: "~> 1.5",
elixirc_paths: elixirc_paths(Mix.env),
compilers: [:phoenix, :gettext] ++ Mix.compilers,
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
aliases: aliases(),
deps: deps()]
[
app: :code_stats,
version: "2.0.0-wip",
elixir: "~> 1.5",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
build_embedded: Mix.env() == :prod,
start_permanent: Mix.env() == :prod,
aliases: aliases(),
deps: deps()
]
end
# Configuration for the OTP application.
......@@ -24,9 +26,9 @@ defmodule CodeStats.Mixfile do
end
# Specifies which paths to compile per environment.
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(:ci), do: ["lib", "test/support"]
defp elixirc_paths(_), do: ["lib"]
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(:ci), do: ["lib", "test/support"]
defp elixirc_paths(_), do: ["lib"]
# Specifies your project dependencies.
#
......@@ -54,8 +56,16 @@ defmodule CodeStats.Mixfile do
{:geolix, "~> 0.14.0"},
{:geolite2data, "~> 0.0.3"},
{:remote_ip, "~> 0.1.3"},
{:distillery, git: "https://github.com/bitwalker/distillery.git", ref: "67905e230ce0e861a739756c1f79ba9124c5fd3e", runtime: false}
]
{
:distillery,
git: "https://github.com/bitwalker/distillery.git",
ref: "67905e230ce0e861a739756c1f79ba9124c5fd3e",
runtime: false
},
{:absinthe, "~> 1.3.2"},
{:absinthe_plug, "~> 1.3.1"},
{:absinthe_ecto, "~> 0.1.2"}
]
end
# Aliases are shortcut or tasks specific to the current project.
......@@ -68,7 +78,7 @@ defmodule CodeStats.Mixfile do
[
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
"ecto.reset": ["ecto.drop", "ecto.setup"],
"test": ["ecto.create --quiet", "ecto.migrate", "test"]
]
test: ["ecto.create --quiet", "ecto.migrate", "test"]
]
end
end
%{"appsignal": {:hex, :appsignal, "1.3.5", "c109a3de233d201dd921e9e17e94fed713792d7b4f724546a89fd29f9e503b59", [:make, :mix], [{:decorator, "~> 1.2.2", [hex: :decorator, repo: "hexpm", optional: false]}, {:httpoison, "~> 0.11", [hex: :httpoison, repo: "hexpm", optional: false]}, {:phoenix, ">= 1.2.0", [hex: :phoenix, repo: "hexpm", optional: true]}, {:plug, ">= 1.1.0", [hex: :plug, repo: "hexpm", optional: true]}, {:poison, ">= 1.3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
%{
"absinthe": {:hex, :absinthe, "1.3.2", "1d16ee5ceeb8b90e37f936b924caacc099b9da667e9c7e6a4d729f41197123d4", [], [], "hexpm"},
"absinthe_ecto": {:hex, :absinthe_ecto, "0.1.2", "bdee4bef46fa2f8ab931a711dc208c817e86d729a145085845de9a6d03c45135", [], [{:absinthe, "~> 1.3.0", [hex: :absinthe, repo: "hexpm", optional: false]}, {:ecto, ">= 0.0.0", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm"},
"absinthe_plug": {:hex, :absinthe_plug, "1.3.1", "e97c9faa6a2e29be181205d994c3ca2e2c5c5dec38aea69fcd324407f6c163c6", [], [{:absinthe, "~> 1.3.0", [hex: :absinthe, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.2 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"appsignal": {:hex, :appsignal, "1.3.5", "c109a3de233d201dd921e9e17e94fed713792d7b4f724546a89fd29f9e503b59", [:make, :mix], [{:decorator, "~> 1.2.2", [hex: :decorator, repo: "hexpm", optional: false]}, {:httpoison, "~> 0.11", [hex: :httpoison, repo: "hexpm", optional: false]}, {:phoenix, ">= 1.2.0", [hex: :phoenix, repo: "hexpm", optional: true]}, {:plug, ">= 1.1.0", [hex: :plug, repo: "hexpm", optional: true]}, {:poison, ">= 1.3.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"bamboo": {:hex, :bamboo, "1.0.0-rc.1", "5e056f4092fea964c83b22827a9e6b5859af2d5793df1cc1f960346183be147c", [:mix], [{:hackney, "~> 1.7", [hex: :hackney, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}, {:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
"bcrypt_elixir": {:hex, :bcrypt_elixir, "1.0.4", "7598efbe9bd56fdc04412b4377a6a3add0bcf8e0cf1f31684190425a404f14e2", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"calendar": {:hex, :calendar, "0.17.4", "22c5e8d98a4db9494396e5727108dffb820ee0d18fed4b0aa8ab76e4f5bc32f1", [:mix], [{:tzdata, "~> 0.5.8 or ~> 0.1.201603", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},
......@@ -44,4 +48,5 @@
"remote_ip": {:hex, :remote_ip, "0.1.3", "9175e63ce23eece9253bdd17edbd2262bd91c5b700987f6ce0044e504ba42089", [:mix], [{:combine, "~> 0.9.2", [hex: :combine, repo: "hexpm", optional: false]}, {:inet_cidr, "~> 1.0", [hex: :inet_cidr, repo: "hexpm", optional: false]}, {:plug, "~> 1.2", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], [], "hexpm"},
"tzdata": {:hex, :tzdata, "0.5.12", "1c17b68692c6ba5b6ab15db3d64cc8baa0f182043d5ae9d4b6d35d70af76f67b", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.3.1", "a1f612a7b512638634a603c8f401892afbf99b8ce93a45041f8aaca99cadb85e", [:rebar3], [], "hexpm"}}
"unicode_util_compat": {:hex, :unicode_util_compat, "0.3.1", "a1f612a7b512638634a603c8f401892afbf99b8ce93a45041f8aaca99cadb85e", [:rebar3], [], "hexpm"},
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment