From 62c74b4be7ad01624ce11a330a330441a21fb830 Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Sat, 19 Mar 2022 15:19:31 -0700 Subject: [PATCH 1/6] Refactor seeds file. --- dev/support/seeds.ex | 323 +++++++++++++++++++++++++++++++++++++++++++ priv/repo/seeds.exs | 312 +---------------------------------------- 2 files changed, 324 insertions(+), 311 deletions(-) create mode 100644 dev/support/seeds.ex diff --git a/dev/support/seeds.ex b/dev/support/seeds.ex new file mode 100644 index 0000000..5372252 --- /dev/null +++ b/dev/support/seeds.ex @@ -0,0 +1,323 @@ +defmodule Flix.Seeds do + import Ecto.Query + + alias Flix.Accounts + alias Flix.Accounts.User + alias Flix.Accounts.UserToken + alias Flix.Catalogs + alias Flix.Catalogs.Genre + alias Flix.Repo + + def run do + # reset database + + reset() + + # create users + + create_users() + + # create genres + + create_genres() + + # create movies + + create_movies() + end + + defp reset() do + Flix.Repo.delete_all("movies") + Flix.Repo.delete_all("genres") + Flix.Repo.delete_all("users") + end + + defp create_users() do + user_data = [ + %{ + name: "Conrad Taylor", + username: "conradwt", + email: "conradwt@example.com", + password: "1qaz2wsx3edc", + password_confirmation: "1qaz2wsx3edc" + }, + %{ + name: "Chief", + username: "chief", + email: "chief@example", + password: "1qaz2wsx3edc", + password_confirmation: "1qaz2wsx3edc" + }, + %{ + name: "Cyborg", + username: "cyborg", + email: "cyborg@example.com", + password: "1qaz2wsx3edc", + password_confirmation: "1qaz2wsx3edc" + }, + %{ + name: "Crazy Jane", + username: "jane", + email: "jane@example.com", + password: "1qaz2wsx3edc", + password_confirmation: "1qaz2wsx3edc" + }, + %{ + name: "Larry Trainor", + username: "larryt", + email: "larryt@example.com", + password: "1qaz2wsx3edc", + password_confirmation: "1qaz2wsx3edc" + }, + %{ + name: "Rita Farr", + username: "ritaf", + email: "ritaf@example.com", + password: "1qaz2wsx3edc", + password_confirmation: "1qaz2wsx3edc" + }, + %{ + name: "Cliff Steele", + username: "cliffs", + email: "cliffs@example.com", + password: "1qaz2wsx3edc", + password_confirmation: "1qaz2wsx3edc" + }, + %{ + name: "Negative Man", + username: "negativem", + email: "negativem@example.com", + password: "1qaz2wsx3edc", + password_confirmation: "1qaz2wsx3edc" + } + ] + + Enum.each(user_data, fn data -> + {:ok, user} = Accounts.register_user(data) + + Ecto.Multi.new() + |> Ecto.Multi.update(:user, User.confirm_changeset(user)) + |> Ecto.Multi.delete_all(:tokens, UserToken.user_and_contexts_query(user, ["confirm"])) + end) + end + + defp create_genres() do + genre_data = ["Action", "Adventure", "Comedy", "Drama", "Sci-Fi"] + + Enum.each(genre_data, fn data -> + Catalogs.create_genre!(%{name: data}) + end) + end + + defp get_genres() do + query = + from(g in Genre, + where: g.name in ["Action", "Adventure", "Sci-Fi"], + order_by: g.name, + select: g.id) + + Repo.all(query) + end + + defp create_movies() do + movie_data = [ + %{ + description: + "After the devastating events of Avengers: Infinity War, the universe is in ruins. With the help of remaining allies, the Avengers assemble once more in order to undo Thanos' actions and restore order to the universe.", + director: "Anthony Russo", + duration: "181 min", + genres: get_genres, + main_image: %Plug.Upload{ + content_type: "image/png", + filename: "avengers-end-game.png", + path: "#{File.cwd!()}/assets/static/images/avengers-end-game.png" + }, + rating: "PG-13", + released_on: "2019-04-26", + title: "My Avengers: Endgame", + total_gross: 1_223_641_414 + }, + %{ + description: + "Carol Danvers becomes one of the universe's most powerful heroes when Earth is caught in the middle of a galactic war between two alien races.", + director: "Anna Boden", + duration: "124 min", + genres: get_genres, + main_image: %Plug.Upload{ + content_type: "image/png", + filename: "avengers-end-game.png", + path: "#{File.cwd!()}/assets/static/images/captain-marvel.png" + }, + rating: "PG-13", + released_on: "2019-03-08", + title: "Captain Marvel", + total_gross: 1_110_662_849 + }, + %{ + description: + "T'Challa, heir to the hidden but advanced kingdom of Wakanda, must step forward to lead his people into a new future and must confront a challenger from his country's past.", + director: "Ryan Coogler", + duration: "134 min", + genres: get_genres, + main_image: %Plug.Upload{ + content_type: "image/png", + filename: "avengers-end-game.png", + path: "#{File.cwd!()}/assets/static/images/black-panther.png" + }, + rating: "PG-13", + released_on: "2018-02-16", + title: "Black Panther", + total_gross: 1_346_913_161 + }, + %{ + description: + "The Avengers and their allies must be willing to sacrifice all in an attempt to defeat the powerful Thanos before his blitz of devastation and ruin puts an end to the universe.", + director: "Anthony Russo", + duration: "149 min", + genres: get_genres, + main_image: %Plug.Upload{ + content_type: "image/png", + filename: "avengers-end-game.png", + path: "#{File.cwd!()}/assets/static/images/avengers-infinity-war.png" + }, + rating: "PG-13", + released_on: "2018-04-27", + title: "Avengers: Infinity War", + total_gross: 2_048_359_754 + }, + %{ + description: + "Reckless test pilot Hal Jordan is granted an alien ring that bestows him with otherworldly powers that inducts him into an intergalactic police force, the Green Lantern Corps.", + director: "Martin Campbell", + duration: "114 min", + genres: get_genres, + main_image: %Plug.Upload{ + content_type: "image/png", + filename: "avengers-end-game.png", + path: "#{File.cwd!()}/assets/static/images/green-lantern.png" + }, + rating: "PG-13", + released_on: "2011-06-17", + title: "Green Lantern", + total_gross: 219_851_172 + }, + %{ + description: + "Four young outsiders teleport to an alternate and dangerous universe which alters their physical form in shocking ways. The four must learn to harness their new abilities and work together to save Earth from a former friend turned enemy.", + director: "Josh Trank", + duration: "100 min", + genres: get_genres, + main_image: %Plug.Upload{ + content_type: "image/png", + filename: "avengers-end-game.png", + path: "#{File.cwd!()}/assets/static/images/fantastic-four.png" + }, + rating: "PG-13", + released_on: "2015-08-07", + title: "Fantastic Four", + total_gross: 168_257_860 + }, + %{ + description: + "When wealthy industrialist Tony Stark is forced to build an armored suit after a life-threatening incident, he ultimately decides to use its technology to fight against evil.", + director: "Jon Favreau", + duration: "126 min", + genres: get_genres, + main_image: %Plug.Upload{ + content_type: "image/png", + filename: "avengers-end-game.png", + path: "#{File.cwd!()}/assets/static/images/ironman.png" + }, + rating: "PG-13", + released_on: "2008-05-02", + title: "Iron Man", + total_gross: 585_366_247 + }, + %{ + description: + "An alien orphan is sent from his dying planet to Earth, where he grows up to become his adoptive home's first and greatest super-hero.", + director: "Richard Donner", + duration: "143 min", + genres: get_genres, + main_image: %Plug.Upload{ + content_type: "image/png", + filename: "avengers-end-game.png", + path: "#{File.cwd!()}/assets/static/images/superman.png" + }, + rating: "PG", + released_on: "1978-12-15", + title: "Superman", + total_gross: 300_451_603 + }, + %{ + description: + "When bitten by a genetically modified spider, a nerdy, shy, and awkward high school student gains spider-like abilities that he eventually must use to fight evil as a superhero after tragedy + befalls his family.", + director: "Sam Raimi", + duration: "121 min", + genres: get_genres, + main_image: %Plug.Upload{ + content_type: "image/png", + filename: "avengers-end-game.png", + path: "#{File.cwd!()}/assets/static/images/spiderman.png" + }, + rating: "PG-13", + released_on: "2002-05-03", + title: "Spider-Man", + total_gross: 825_025_036 + }, + %{ + description: + "The Dark Knight of Gotham City begins his war on crime with his first major enemy being the clownishly homicidal Joker.", + director: "Tim Burton", + duration: "126 min", + genres: get_genres, + main_image: %Plug.Upload{ + content_type: "image/png", + filename: "avengers-end-game.png", + path: "#{File.cwd!()}/assets/static/images/batman.png" + }, + rating: "PG-13", + released_on: "1989-06-23", + title: "Batman", + total_gross: 411_348_924 + }, + %{ + description: + "Patience Philips seems destined to spend her life apologizing for taking up space. Despite her artistic ability she has a more than respectable career as a graphic designer.", + director: "Jean-Christophe 'Pitof' Comar", + duration: "101 min", + genres: get_genres, + main_image: %Plug.Upload{ + content_type: "image/png", + filename: "avengers-end-game.png", + path: "#{File.cwd!()}/assets/static/images/catwoman.png" + }, + rating: "PG-13", + released_on: "2004-07-23", + title: "Catwoman", + total_gross: 82_102_379 + }, + %{ + description: + "When a pilot crashes and tells of conflict in the outside world, Diana, an Amazonian warrior in training, leaves home to fight a war, discovering her full powers and true destiny.", + director: "Patty Jenkins", + duration: "141 min", + genres: get_genres, + main_image: %Plug.Upload{ + content_type: "image/png", + filename: "avengers-end-game.png", + path: "#{File.cwd!()}/assets/static/images/wonder-woman.png" + }, + rating: "PG-13", + released_on: "2017-06-02", + title: "Wonder Woman", + total_gross: 821_847_012 + } + ] + + Enum.each(movie_data, fn data -> + Catalogs.create_movie(data) + end) + end +end diff --git a/priv/repo/seeds.exs b/priv/repo/seeds.exs index 36b6a8b..af2409b 100644 --- a/priv/repo/seeds.exs +++ b/priv/repo/seeds.exs @@ -18,314 +18,4 @@ # movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }]) # Character.create(name: 'Luke', movie: movies.first) -import Ecto.Query - -alias Flix.Accounts -alias Flix.Catalogs -alias Flix.Catalogs.Genre -alias Flix.Repo - -# clear database - -Flix.Repo.delete_all("movies") -Flix.Repo.delete_all("genres") -Flix.Repo.delete_all("users") - -# create users - -user_data = [ - %{ - name: "Conrad Taylor", - username: "conradwt", - email: "conradwt@example.com", - password: "1qaz2wsx3edc", - password_confirmation: "1qaz2wsx3edc", - admin: true, - confirmed_at: NaiveDateTime.utc_now() - }, - %{ - name: "Chief", - username: "chief", - email: "chief@example", - password: "1qaz2wsx3edc", - password_confirmation: "1qaz2wsx3edc", - admin: true, - confirmed_at: NaiveDateTime.utc_now() - }, - %{ - name: "Cyborg", - username: "cyborg", - email: "cyborg@example.com", - password: "1qaz2wsx3edc", - password_confirmation: "1qaz2wsx3edc", - admin: true, - confirmed_at: NaiveDateTime.utc_now() - }, - %{ - name: "Crazy Jane", - username: "jane", - email: "jane@example.com", - password: "1qaz2wsx3edc", - password_confirmation: "1qaz2wsx3edc", - admin: true, - confirmed_at: NaiveDateTime.utc_now() - }, - %{ - name: "Larry Trainor", - username: "larryt", - email: "larryt@example.com", - password: "1qaz2wsx3edc", - password_confirmation: "1qaz2wsx3edc", - admin: true, - confirmed_at: NaiveDateTime.utc_now() - }, - %{ - name: "Rita Farr", - username: "ritaf", - email: "ritaf@example.com", - password: "1qaz2wsx3edc", - password_confirmation: "1qaz2wsx3edc", - admin: true, - confirmed_at: NaiveDateTime.utc_now() - }, - %{ - name: "Cliff Steele", - username: "cliffs", - email: "cliffs@example.com", - password: "1qaz2wsx3edc", - password_confirmation: "1qaz2wsx3edc", - admin: true, - confirmed_at: NaiveDateTime.utc_now() - }, - %{ - name: "Negative Man", - username: "negativem", - email: "negativem@example.com", - password: "1qaz2wsx3edc", - password_confirmation: "1qaz2wsx3edc", - admin: true, - confirmed_at: NaiveDateTime.utc_now() - } -] - -Enum.each(user_data, fn data -> - Accounts.register_user(data) -end) - -# create genres - -genre_data = ["Action", "Adventure", "Comedy", "Drama", "Sci-Fi"] - -Enum.each(genre_data, fn data -> - Catalogs.create_genre!(%{name: data}) -end) - -query = - from(g in Genre, - where: g.name in ["Action", "Adventure", "Sci-Fi"], - order_by: g.name, - select: g.id) - -get_genres = Repo.all(query) - -# create movies - -movie_data = [ - %{ - description: - "After the devastating events of Avengers: Infinity War, the universe is in ruins. With the help of remaining allies, the Avengers assemble once more in order to undo Thanos' actions and restore order to the universe.", - director: "Anthony Russo", - duration: "181 min", - genres: get_genres, - main_image: %Plug.Upload{ - content_type: "image/png", - filename: "avengers-end-game.png", - path: "#{File.cwd!()}/assets/static/images/avengers-end-game.png" - }, - rating: "PG-13", - released_on: "2019-04-26", - title: "My Avengers: Endgame", - total_gross: 1_223_641_414 - }, - %{ - description: - "Carol Danvers becomes one of the universe's most powerful heroes when Earth is caught in the middle of a galactic war between two alien races.", - director: "Anna Boden", - duration: "124 min", - genres: get_genres, - main_image: %Plug.Upload{ - content_type: "image/png", - filename: "avengers-end-game.png", - path: "#{File.cwd!()}/assets/static/images/captain-marvel.png" - }, - rating: "PG-13", - released_on: "2019-03-08", - title: "Captain Marvel", - total_gross: 1_110_662_849 - }, - %{ - description: - "T'Challa, heir to the hidden but advanced kingdom of Wakanda, must step forward to lead his people into a new future and must confront a challenger from his country's past.", - director: "Ryan Coogler", - duration: "134 min", - genres: get_genres, - main_image: %Plug.Upload{ - content_type: "image/png", - filename: "avengers-end-game.png", - path: "#{File.cwd!()}/assets/static/images/black-panther.png" - }, - rating: "PG-13", - released_on: "2018-02-16", - title: "Black Panther", - total_gross: 1_346_913_161 - }, - %{ - description: - "The Avengers and their allies must be willing to sacrifice all in an attempt to defeat the powerful Thanos before his blitz of devastation and ruin puts an end to the universe.", - director: "Anthony Russo", - duration: "149 min", - genres: get_genres, - main_image: %Plug.Upload{ - content_type: "image/png", - filename: "avengers-end-game.png", - path: "#{File.cwd!()}/assets/static/images/avengers-infinity-war.png" - }, - rating: "PG-13", - released_on: "2018-04-27", - title: "Avengers: Infinity War", - total_gross: 2_048_359_754 - }, - %{ - description: - "Reckless test pilot Hal Jordan is granted an alien ring that bestows him with otherworldly powers that inducts him into an intergalactic police force, the Green Lantern Corps.", - director: "Martin Campbell", - duration: "114 min", - genres: get_genres, - main_image: %Plug.Upload{ - content_type: "image/png", - filename: "avengers-end-game.png", - path: "#{File.cwd!()}/assets/static/images/green-lantern.png" - }, - rating: "PG-13", - released_on: "2011-06-17", - title: "Green Lantern", - total_gross: 219_851_172 - }, - %{ - description: - "Four young outsiders teleport to an alternate and dangerous universe which alters their physical form in shocking ways. The four must learn to harness their new abilities and work together to save Earth from a former friend turned enemy.", - director: "Josh Trank", - duration: "100 min", - genres: get_genres, - main_image: %Plug.Upload{ - content_type: "image/png", - filename: "avengers-end-game.png", - path: "#{File.cwd!()}/assets/static/images/fantastic-four.png" - }, - rating: "PG-13", - released_on: "2015-08-07", - title: "Fantastic Four", - total_gross: 168_257_860 - }, - %{ - description: - "When wealthy industrialist Tony Stark is forced to build an armored suit after a life-threatening incident, he ultimately decides to use its technology to fight against evil.", - director: "Jon Favreau", - duration: "126 min", - genres: get_genres, - main_image: %Plug.Upload{ - content_type: "image/png", - filename: "avengers-end-game.png", - path: "#{File.cwd!()}/assets/static/images/ironman.png" - }, - rating: "PG-13", - released_on: "2008-05-02", - title: "Iron Man", - total_gross: 585_366_247 - }, - %{ - description: - "An alien orphan is sent from his dying planet to Earth, where he grows up to become his adoptive home's first and greatest super-hero.", - director: "Richard Donner", - duration: "143 min", - genres: get_genres, - main_image: %Plug.Upload{ - content_type: "image/png", - filename: "avengers-end-game.png", - path: "#{File.cwd!()}/assets/static/images/superman.png" - }, - rating: "PG", - released_on: "1978-12-15", - title: "Superman", - total_gross: 300_451_603 - }, - %{ - description: - "When bitten by a genetically modified spider, a nerdy, shy, and awkward high school student gains spider-like abilities that he eventually must use to fight evil as a superhero after tragedy - befalls his family.", - director: "Sam Raimi", - duration: "121 min", - genres: get_genres, - main_image: %Plug.Upload{ - content_type: "image/png", - filename: "avengers-end-game.png", - path: "#{File.cwd!()}/assets/static/images/spiderman.png" - }, - rating: "PG-13", - released_on: "2002-05-03", - title: "Spider-Man", - total_gross: 825_025_036 - }, - %{ - description: - "The Dark Knight of Gotham City begins his war on crime with his first major enemy being the clownishly homicidal Joker.", - director: "Tim Burton", - duration: "126 min", - genres: get_genres, - main_image: %Plug.Upload{ - content_type: "image/png", - filename: "avengers-end-game.png", - path: "#{File.cwd!()}/assets/static/images/batman.png" - }, - rating: "PG-13", - released_on: "1989-06-23", - title: "Batman", - total_gross: 411_348_924 - }, - %{ - description: - "Patience Philips seems destined to spend her life apologizing for taking up space. Despite her artistic ability she has a more than respectable career as a graphic designer.", - director: "Jean-Christophe 'Pitof' Comar", - duration: "101 min", - genres: get_genres, - main_image: %Plug.Upload{ - content_type: "image/png", - filename: "avengers-end-game.png", - path: "#{File.cwd!()}/assets/static/images/catwoman.png" - }, - rating: "PG-13", - released_on: "2004-07-23", - title: "Catwoman", - total_gross: 82_102_379 - }, - %{ - description: - "When a pilot crashes and tells of conflict in the outside world, Diana, an Amazonian warrior in training, leaves home to fight a war, discovering her full powers and true destiny.", - director: "Patty Jenkins", - duration: "141 min", - genres: get_genres, - main_image: %Plug.Upload{ - content_type: "image/png", - filename: "avengers-end-game.png", - path: "#{File.cwd!()}/assets/static/images/wonder-woman.png" - }, - rating: "PG-13", - released_on: "2017-06-02", - title: "Wonder Woman", - total_gross: 821_847_012 - } -] - -Enum.each(movie_data, fn data -> - Catalogs.create_movie(data) -end) +Flix.Seeds.run() From c8ad902a68a340883f69ed453345ac00d9f0f29b Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Sat, 19 Mar 2022 16:11:19 -0700 Subject: [PATCH 2/6] Code cleanup. --- dev/support/seeds.ex | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/dev/support/seeds.ex b/dev/support/seeds.ex index 5372252..640332d 100644 --- a/dev/support/seeds.ex +++ b/dev/support/seeds.ex @@ -126,7 +126,7 @@ defmodule Flix.Seeds do "After the devastating events of Avengers: Infinity War, the universe is in ruins. With the help of remaining allies, the Avengers assemble once more in order to undo Thanos' actions and restore order to the universe.", director: "Anthony Russo", duration: "181 min", - genres: get_genres, + genres: get_genres(), main_image: %Plug.Upload{ content_type: "image/png", filename: "avengers-end-game.png", @@ -142,7 +142,7 @@ defmodule Flix.Seeds do "Carol Danvers becomes one of the universe's most powerful heroes when Earth is caught in the middle of a galactic war between two alien races.", director: "Anna Boden", duration: "124 min", - genres: get_genres, + genres: get_genres(), main_image: %Plug.Upload{ content_type: "image/png", filename: "avengers-end-game.png", @@ -158,7 +158,7 @@ defmodule Flix.Seeds do "T'Challa, heir to the hidden but advanced kingdom of Wakanda, must step forward to lead his people into a new future and must confront a challenger from his country's past.", director: "Ryan Coogler", duration: "134 min", - genres: get_genres, + genres: get_genres(), main_image: %Plug.Upload{ content_type: "image/png", filename: "avengers-end-game.png", @@ -174,7 +174,7 @@ defmodule Flix.Seeds do "The Avengers and their allies must be willing to sacrifice all in an attempt to defeat the powerful Thanos before his blitz of devastation and ruin puts an end to the universe.", director: "Anthony Russo", duration: "149 min", - genres: get_genres, + genres: get_genres(), main_image: %Plug.Upload{ content_type: "image/png", filename: "avengers-end-game.png", @@ -190,7 +190,7 @@ defmodule Flix.Seeds do "Reckless test pilot Hal Jordan is granted an alien ring that bestows him with otherworldly powers that inducts him into an intergalactic police force, the Green Lantern Corps.", director: "Martin Campbell", duration: "114 min", - genres: get_genres, + genres: get_genres(), main_image: %Plug.Upload{ content_type: "image/png", filename: "avengers-end-game.png", @@ -206,7 +206,7 @@ defmodule Flix.Seeds do "Four young outsiders teleport to an alternate and dangerous universe which alters their physical form in shocking ways. The four must learn to harness their new abilities and work together to save Earth from a former friend turned enemy.", director: "Josh Trank", duration: "100 min", - genres: get_genres, + genres: get_genres(), main_image: %Plug.Upload{ content_type: "image/png", filename: "avengers-end-game.png", @@ -222,7 +222,7 @@ defmodule Flix.Seeds do "When wealthy industrialist Tony Stark is forced to build an armored suit after a life-threatening incident, he ultimately decides to use its technology to fight against evil.", director: "Jon Favreau", duration: "126 min", - genres: get_genres, + genres: get_genres(), main_image: %Plug.Upload{ content_type: "image/png", filename: "avengers-end-game.png", @@ -238,7 +238,7 @@ defmodule Flix.Seeds do "An alien orphan is sent from his dying planet to Earth, where he grows up to become his adoptive home's first and greatest super-hero.", director: "Richard Donner", duration: "143 min", - genres: get_genres, + genres: get_genres(), main_image: %Plug.Upload{ content_type: "image/png", filename: "avengers-end-game.png", @@ -255,7 +255,7 @@ defmodule Flix.Seeds do befalls his family.", director: "Sam Raimi", duration: "121 min", - genres: get_genres, + genres: get_genres(), main_image: %Plug.Upload{ content_type: "image/png", filename: "avengers-end-game.png", @@ -271,7 +271,7 @@ defmodule Flix.Seeds do "The Dark Knight of Gotham City begins his war on crime with his first major enemy being the clownishly homicidal Joker.", director: "Tim Burton", duration: "126 min", - genres: get_genres, + genres: get_genres(), main_image: %Plug.Upload{ content_type: "image/png", filename: "avengers-end-game.png", @@ -287,7 +287,7 @@ defmodule Flix.Seeds do "Patience Philips seems destined to spend her life apologizing for taking up space. Despite her artistic ability she has a more than respectable career as a graphic designer.", director: "Jean-Christophe 'Pitof' Comar", duration: "101 min", - genres: get_genres, + genres: get_genres(), main_image: %Plug.Upload{ content_type: "image/png", filename: "avengers-end-game.png", @@ -303,7 +303,7 @@ defmodule Flix.Seeds do "When a pilot crashes and tells of conflict in the outside world, Diana, an Amazonian warrior in training, leaves home to fight a war, discovering her full powers and true destiny.", director: "Patty Jenkins", duration: "141 min", - genres: get_genres, + genres: get_genres(), main_image: %Plug.Upload{ content_type: "image/png", filename: "avengers-end-game.png", From 7bc5b162160029069d8e4235f487ceaa370605eb Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Fri, 25 Mar 2022 12:17:32 -0700 Subject: [PATCH 3/6] WIP: add GraphQL authentication. --- .iex.exs | 2 + config/config.exs | 4 +- dev/support/seeds.ex | 2 + lib/flix/accounts.ex | 24 ++++++++++++ lib/flix/accounts/user.ex | 8 +--- lib/flix/application.ex | 5 ++- lib/flix/catalogs.ex | 2 +- lib/flix_web/channels/user_socket.ex | 3 +- lib/flix_web/controllers/movie_controller.ex | 4 +- lib/flix_web/endpoint.ex | 4 +- lib/flix_web/graphql/changeset_errors.ex | 15 ++++++++ .../graphql/middleware/authenticate.ex | 14 +++++++ lib/flix_web/graphql/resolvers/accounts.ex | 38 +++++++++++++++++++ .../graphql/resolvers/genre_resolver.ex | 2 +- .../graphql/resolvers/movie_resolver.ex | 2 +- .../graphql/resolvers/review_resolver.ex | 2 +- .../graphql/resolvers/user_resolver.ex | 6 +-- lib/flix_web/graphql/schema.ex | 19 ++++++++-- .../graphql/schemas/mutations/accounts.ex | 23 +++++++++++ .../graphql/schemas/mutations/catalogs.ex | 2 + lib/flix_web/graphql/schemas/queries/movie.ex | 8 ++-- lib/flix_web/graphql/schemas/queries/user.ex | 4 +- lib/flix_web/graphql/types/custom/uuid4.ex | 36 ++++++++++++++++++ lib/flix_web/graphql/types/genre.ex | 2 +- lib/flix_web/graphql/types/movie.ex | 6 +-- lib/flix_web/graphql/types/review.ex | 2 +- lib/flix_web/graphql/types/session.ex | 8 ++++ lib/flix_web/graphql/types/user.ex | 2 +- lib/flix_web/plugs/set_current_user.ex | 32 ++++++++++++++++ lib/flix_web/router.ex | 11 +++--- mix.exs | 4 +- mix.lock | 3 +- 32 files changed, 253 insertions(+), 46 deletions(-) create mode 100644 lib/flix_web/graphql/changeset_errors.ex create mode 100644 lib/flix_web/graphql/middleware/authenticate.ex create mode 100644 lib/flix_web/graphql/resolvers/accounts.ex create mode 100644 lib/flix_web/graphql/schemas/mutations/accounts.ex create mode 100644 lib/flix_web/graphql/schemas/mutations/catalogs.ex create mode 100644 lib/flix_web/graphql/types/custom/uuid4.ex create mode 100644 lib/flix_web/graphql/types/session.ex create mode 100644 lib/flix_web/plugs/set_current_user.ex diff --git a/.iex.exs b/.iex.exs index 2d0eae8..41a5b9e 100644 --- a/.iex.exs +++ b/.iex.exs @@ -2,6 +2,8 @@ IEx.configure(inspect: [charlists: false]) alias Flix.Accounts alias Flix.Accounts.User +alias Flix.Accounts.UserToken +alias Flix.Accounts.UserNotifier alias Flix.Catalogs alias Flix.Catalogs.Characterization diff --git a/config/config.exs b/config/config.exs index 961cf22..03cc928 100644 --- a/config/config.exs +++ b/config/config.exs @@ -59,8 +59,8 @@ config :flix, Flix.Mailer, # end # Configure Absinthe SDL/JSON code generation. -config :absinthe, - schema: FlixWeb.Graphql.Schema +# config :absinthe, +# schema: FlixWeb.GraphQL.Schema # Import environment specific config. This must remain at the bottom # of this file so it overrides the configuration defined above. diff --git a/dev/support/seeds.ex b/dev/support/seeds.ex index 640332d..45a3a30 100644 --- a/dev/support/seeds.ex +++ b/dev/support/seeds.ex @@ -30,6 +30,8 @@ defmodule Flix.Seeds do Flix.Repo.delete_all("movies") Flix.Repo.delete_all("genres") Flix.Repo.delete_all("users") + Flix.Repo.delete_all("users") + Flix.Repo.delete_all("users_tokens") end defp create_users() do diff --git a/lib/flix/accounts.ex b/lib/flix/accounts.ex index 248fe27..4e7d923 100644 --- a/lib/flix/accounts.ex +++ b/lib/flix/accounts.ex @@ -59,6 +59,30 @@ defmodule Flix.Accounts do if User.valid_password?(user, password), do: user end + @doc """ + Gets a user by email and password. + + ## Examples + + iex> authenticate("foo@example.com", "correct_password") + {:ok, %User{}} + + iex> authenticate("foo@example.com", "invalid_password") + :error + + """ + def authenticate(email, password) + when is_binary(email) and is_binary(password) do + + user = Repo.get_by(User, email: email) + + with true <- User.valid_password?(user, password) do + {:ok, user} + else + _ -> :error + end + end + @doc """ Gets a single user. diff --git a/lib/flix/accounts/user.ex b/lib/flix/accounts/user.ex index cfd1755..dca5bf7 100644 --- a/lib/flix/accounts/user.ex +++ b/lib/flix/accounts/user.ex @@ -45,19 +45,13 @@ defmodule Flix.Accounts.User do """ def registration_changeset(user, attrs, opts \\ []) do user - |> cast(attrs, [:admin, :email, :name, :password, :username]) - |> validate_admin() + |> cast(attrs, [:email, :name, :password, :username]) |> validate_email() |> validate_password(opts) |> validate_name |> validate_username() end - defp validate_admin(changeset) do - changeset - |> validate_required([:admin]) - end - defp validate_name(changeset) do changeset |> validate_required([:name]) diff --git a/lib/flix/application.ex b/lib/flix/application.ex index c87c15a..cd4d1f6 100644 --- a/lib/flix/application.ex +++ b/lib/flix/application.ex @@ -12,11 +12,12 @@ defmodule Flix.Application do # Start the Telemetry supervisor FlixWeb.Telemetry, # Start the PubSub system - {Phoenix.PubSub, name: Flix.PubSub}, + {Phoenix.PubSub, [name: Flix.PubSub, adapter: Phoenix.PubSub.PG2]}, # Start the Endpoint (http/https) - FlixWeb.Endpoint + FlixWeb.Endpoint, # Start a worker by calling: Flix.Worker.start_link(arg) # {Flix.Worker, arg} + {Absinthe.Subscription, FlixWeb.Endpoint} ] # See https://hexdocs.pm/elixir/Supervisor.html diff --git a/lib/flix/catalogs.ex b/lib/flix/catalogs.ex index 56def3e..652a6ca 100644 --- a/lib/flix/catalogs.ex +++ b/lib/flix/catalogs.ex @@ -72,7 +72,7 @@ defmodule Flix.Catalogs do """ def create_movie(attrs \\ %{}) do Ecto.Multi.new() - |> Ecto.Multi.insert(:movie_info, Movie.changeset(%Movie{}, attrs)) + |> Ecto.Multi.insert(:movie, Movie.changeset(%Movie{}, attrs)) |> Ecto.Multi.update(:movie_poster, &Movie.poster_changeset(&1.movie, attrs)) |> Repo.transaction() end diff --git a/lib/flix_web/channels/user_socket.ex b/lib/flix_web/channels/user_socket.ex index 1a59ede..cc84f80 100644 --- a/lib/flix_web/channels/user_socket.ex +++ b/lib/flix_web/channels/user_socket.ex @@ -1,5 +1,6 @@ -defmodule FlixWeb.UserSocket do +defmodule FlixWeb.Channels.UserSocket do use Phoenix.Socket + use Absinthe.Phoenix.Socket, schema: FlixWeb.GraphQL.Schema ## Channels # channel "room:*", FlixWeb.RoomChannel diff --git a/lib/flix_web/controllers/movie_controller.ex b/lib/flix_web/controllers/movie_controller.ex index bbe6682..7b69d63 100644 --- a/lib/flix_web/controllers/movie_controller.ex +++ b/lib/flix_web/controllers/movie_controller.ex @@ -31,10 +31,10 @@ defmodule FlixWeb.MovieController do def create(conn, %{"movie" => movie_params}) do case Catalogs.create_movie(movie_params) do - {:ok, %{movie_info: movie_info, movie_poster: _movie_poster}} -> + {:ok, %{movie: movie, movie_poster: _movie_poster}} -> conn |> put_flash(:notice, "Movie created successfully.") - |> redirect(to: Routes.movie_path(conn, :show, movie_info)) + |> redirect(to: Routes.movie_path(conn, :show, movie)) {:error, :movie_info, changeset, _changes_so_far} -> conn diff --git a/lib/flix_web/endpoint.ex b/lib/flix_web/endpoint.ex index 7ac53d4..4424884 100644 --- a/lib/flix_web/endpoint.ex +++ b/lib/flix_web/endpoint.ex @@ -1,5 +1,6 @@ defmodule FlixWeb.Endpoint do use Phoenix.Endpoint, otp_app: :flix + use Absinthe.Phoenix.Endpoint # The session will be stored in the cookie and signed, # this means its contents can be read but not tampered with. @@ -10,10 +11,9 @@ defmodule FlixWeb.Endpoint do signing_salt: "NFzKYqak" ] - socket("/socket", FlixWeb.UserSocket, + socket "/socket", FlixWeb.Channels.UserSocket, websocket: [timeout: 45_000], longpoll: false - ) socket("/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]]) diff --git a/lib/flix_web/graphql/changeset_errors.ex b/lib/flix_web/graphql/changeset_errors.ex new file mode 100644 index 0000000..59df053 --- /dev/null +++ b/lib/flix_web/graphql/changeset_errors.ex @@ -0,0 +1,15 @@ +defmodule FlixWeb.GraphQL.ChangesetErrors do + @doc """ + Traverses the changeset errors and returns a map of + error messages. For example: + + %{title: ["can't be blank"], released_on: ["can't be blank"]} + """ + def error_details(changeset) do + Ecto.Changeset.traverse_errors(changeset, fn {msg, opts} -> + Enum.reduce(opts, msg, fn {key, value}, acc -> + String.replace(acc, "%{#{key}}", to_string(value)) + end) + end) + end +end diff --git a/lib/flix_web/graphql/middleware/authenticate.ex b/lib/flix_web/graphql/middleware/authenticate.ex new file mode 100644 index 0000000..5c93dc9 --- /dev/null +++ b/lib/flix_web/graphql/middleware/authenticate.ex @@ -0,0 +1,14 @@ +defmodule FlixWeb.GraphQL.Middleware.Authenticate do + @behaviour Absinthe.Middleware + + def call(resolution, _config) do + case resolution.context do + %{current_user: _} -> + resolution + + _ -> + resolution + |> Absinthe.Resolution.put_result({:error, "You must sign in first!"}) + end + end +end diff --git a/lib/flix_web/graphql/resolvers/accounts.ex b/lib/flix_web/graphql/resolvers/accounts.ex new file mode 100644 index 0000000..5cb15ad --- /dev/null +++ b/lib/flix_web/graphql/resolvers/accounts.ex @@ -0,0 +1,38 @@ +defmodule FlixWeb.GraphQL.Resolvers.Accounts do + alias Flix.Accounts + alias FlixWeb.GraphQL.ChangesetErrors + + def signin(_parent, %{email: email, password: password}, _resolution) do + case Accounts.authenticate(email, password) do + :error -> + {:error, "Whoops, invalid credentials!"} + + {:ok, user} -> + token = Accounts.generate_user_session_token(user) + {:ok, %{user: user, token: token}} + end + end + + def signup(_parent, args, _resolution) do + case Accounts.register_user(args) do + {:error, changeset} -> + { + :error, + message: "Could not create account", + details: ChangesetErrors.error_details(changeset) + } + + {:ok, user} -> + token = Accounts.generate_user_session_token(user) + {:ok, %{user: user, token: token}} + end + end + + def me(_parent, _args, %{context: %{current_user: user}}) do + {:ok, user} + end + + def me(_parent, _args, _resolution) do + {:ok, nil} + end +end diff --git a/lib/flix_web/graphql/resolvers/genre_resolver.ex b/lib/flix_web/graphql/resolvers/genre_resolver.ex index 1a9c549..4fde250 100644 --- a/lib/flix_web/graphql/resolvers/genre_resolver.ex +++ b/lib/flix_web/graphql/resolvers/genre_resolver.ex @@ -1,4 +1,4 @@ -defmodule FlixWeb.Graphql.Resolvers.GenreResolver do +defmodule FlixWeb.GraphQL.Resolvers.GenreResolver do alias Flix.Catalogs def list_genres(%Flix.Catalogs.Movie{} = movie, _args, _resolution) do diff --git a/lib/flix_web/graphql/resolvers/movie_resolver.ex b/lib/flix_web/graphql/resolvers/movie_resolver.ex index 262f6f4..4d58d97 100644 --- a/lib/flix_web/graphql/resolvers/movie_resolver.ex +++ b/lib/flix_web/graphql/resolvers/movie_resolver.ex @@ -1,4 +1,4 @@ -defmodule FlixWeb.Graphql.Resolvers.MovieResolver do +defmodule FlixWeb.GraphQL.Resolvers.MovieResolver do alias Flix.Catalogs alias Flix.Catalogs.Movie alias Flix.Repo diff --git a/lib/flix_web/graphql/resolvers/review_resolver.ex b/lib/flix_web/graphql/resolvers/review_resolver.ex index 1c06091..eb3b385 100644 --- a/lib/flix_web/graphql/resolvers/review_resolver.ex +++ b/lib/flix_web/graphql/resolvers/review_resolver.ex @@ -1,4 +1,4 @@ -defmodule FlixWeb.Graphql.Resolvers.ReviewResolver do +defmodule FlixWeb.GraphQL.Resolvers.ReviewResolver do alias Flix.Catalogs def list_reviews(%Flix.Catalogs.Movie{} = movie, _args, _resolution) do diff --git a/lib/flix_web/graphql/resolvers/user_resolver.ex b/lib/flix_web/graphql/resolvers/user_resolver.ex index 65087cb..815e04e 100644 --- a/lib/flix_web/graphql/resolvers/user_resolver.ex +++ b/lib/flix_web/graphql/resolvers/user_resolver.ex @@ -1,16 +1,16 @@ -defmodule FlixWeb.Graphql.Resolvers.UserResolver do +defmodule FlixWeb.GraphQL.Resolvers.UserResolver do alias Flix.Accounts alias Flix.Accounts.User alias Flix.Repo - def get_user(_root, %{id: id}, _info) do + def get_user(_parent, %{id: id}, _resolution) do case User |> Repo.get(id) do nil -> {:error, "User id \"#{id}\" not found"} user -> {:ok, user} end end - def list_users(_root, _args, _info) do + def list_users(_parent, _args, _resolution) do {:ok, Accounts.list_users()} end end diff --git a/lib/flix_web/graphql/schema.ex b/lib/flix_web/graphql/schema.ex index 1c9a40b..9162ae0 100644 --- a/lib/flix_web/graphql/schema.ex +++ b/lib/flix_web/graphql/schema.ex @@ -1,14 +1,19 @@ -defmodule FlixWeb.Graphql.Schema do +defmodule FlixWeb.GraphQL.Schema do use Absinthe.Schema - import_types(FlixWeb.Graphql.Types.{ + import_types Absinthe.Type.Custom + + import_types(FlixWeb.GraphQL.Types.Custom.UUID4) + + import_types(FlixWeb.GraphQL.Types.{ Genre, Movie, Review, + Session, User }) - import_types(FlixWeb.Graphql.Schemas.Queries.{ + import_types(FlixWeb.GraphQL.Schemas.Queries.{ Movie, User }) @@ -17,4 +22,12 @@ defmodule FlixWeb.Graphql.Schema do import_fields(:movie_queries) import_fields(:user_queries) end + + import_types(FlixWeb.GraphQL.Schemas.Mutations.{ + Accounts + }) + + mutation do + import_fields(:user_mutations) + end end diff --git a/lib/flix_web/graphql/schemas/mutations/accounts.ex b/lib/flix_web/graphql/schemas/mutations/accounts.ex new file mode 100644 index 0000000..41b6b3f --- /dev/null +++ b/lib/flix_web/graphql/schemas/mutations/accounts.ex @@ -0,0 +1,23 @@ +defmodule FlixWeb.GraphQL.Schemas.Mutations.Accounts do + use Absinthe.Schema.Notation + + alias FlixWeb.GraphQL.Resolvers + + object :user_mutations do + @desc "Create a user account" + field :signup, :session do + arg :name, non_null(:string) + arg :email, non_null(:string) + arg :username, non_null(:string) + arg :password, non_null(:string) + resolve &Resolvers.Accounts.signup/3 + end + + @desc "Sign in a user" + field :signin, :session do + arg :email, non_null(:string) + arg :password, non_null(:string) + resolve &Resolvers.Accounts.signin/3 + end + end +end diff --git a/lib/flix_web/graphql/schemas/mutations/catalogs.ex b/lib/flix_web/graphql/schemas/mutations/catalogs.ex new file mode 100644 index 0000000..8425be6 --- /dev/null +++ b/lib/flix_web/graphql/schemas/mutations/catalogs.ex @@ -0,0 +1,2 @@ +defmodule FlixWeb.GraphQL.Schemas.Mutations.Catalogs do +end diff --git a/lib/flix_web/graphql/schemas/queries/movie.ex b/lib/flix_web/graphql/schemas/queries/movie.ex index 7bc127c..702b084 100644 --- a/lib/flix_web/graphql/schemas/queries/movie.ex +++ b/lib/flix_web/graphql/schemas/queries/movie.ex @@ -1,21 +1,21 @@ -defmodule FlixWeb.Graphql.Schemas.Queries.Movie do +defmodule FlixWeb.GraphQL.Schemas.Queries.Movie do use Absinthe.Schema.Notation - alias FlixWeb.Graphql.Resolvers.MovieResolver + alias FlixWeb.GraphQL.Resolvers object :movie_queries do @desc "get a single movie" field :movie, :movie do arg :id, non_null(:id) - resolve(&MovieResolver.get_movie/3) + resolve(&Resolvers.MovieResolver.get_movie/3) end @desc "list all movies" field :movies, list_of(:movie) do arg(:filter, :string, default_value: nil) - resolve(&MovieResolver.list_movies/3) + resolve(&Resolvers.MovieResolver.list_movies/3) end end end diff --git a/lib/flix_web/graphql/schemas/queries/user.ex b/lib/flix_web/graphql/schemas/queries/user.ex index 6a984f6..fb828e1 100644 --- a/lib/flix_web/graphql/schemas/queries/user.ex +++ b/lib/flix_web/graphql/schemas/queries/user.ex @@ -1,7 +1,7 @@ -defmodule FlixWeb.Graphql.Schemas.Queries.User do +defmodule FlixWeb.GraphQL.Schemas.Queries.User do use Absinthe.Schema.Notation - alias FlixWeb.Graphql.Resolvers.UserResolver + alias FlixWeb.GraphQL.Resolvers.UserResolver object :user_queries do @desc "get a single user" diff --git a/lib/flix_web/graphql/types/custom/uuid4.ex b/lib/flix_web/graphql/types/custom/uuid4.ex new file mode 100644 index 0000000..91414af --- /dev/null +++ b/lib/flix_web/graphql/types/custom/uuid4.ex @@ -0,0 +1,36 @@ +defmodule FlixWeb.GraphQL.Types.Custom.UUID4 do + @moduledoc """ + The UUID4 scalar type allows UUID4 compliant strings to be passed in and out. + Requires `{ :ecto, ">= 0.0.0" }` package: https://github.com/elixir-ecto/ecto + """ + use Absinthe.Schema.Notation + + alias Ecto.UUID + + scalar :uuid4, name: "UUID4" do + description(""" + The `UUID4` scalar type represents UUID4 compliant string data, represented as UTF-8 + character sequences. The UUID4 type is most often used to represent unique + human-readable ID strings. + """) + + serialize(&encode/1) + parse(&decode/1) + end + + @spec decode(Absinthe.Blueprint.Input.String.t()) :: {:ok, term()} | :error + @spec decode(Absinthe.Blueprint.Input.Null.t()) :: {:ok, nil} + defp decode(%Absinthe.Blueprint.Input.String{value: value}) do + UUID.cast(value) + end + + defp decode(%Absinthe.Blueprint.Input.Null{}) do + {:ok, nil} + end + + defp decode(_) do + :error + end + + defp encode(value), do: value +end diff --git a/lib/flix_web/graphql/types/genre.ex b/lib/flix_web/graphql/types/genre.ex index 1dcf960..909e184 100644 --- a/lib/flix_web/graphql/types/genre.ex +++ b/lib/flix_web/graphql/types/genre.ex @@ -1,4 +1,4 @@ -defmodule FlixWeb.Graphql.Types.Genre do +defmodule FlixWeb.GraphQL.Types.Genre do use Absinthe.Schema.Notation @desc "a genre" diff --git a/lib/flix_web/graphql/types/movie.ex b/lib/flix_web/graphql/types/movie.ex index 7fe2ec1..179c760 100644 --- a/lib/flix_web/graphql/types/movie.ex +++ b/lib/flix_web/graphql/types/movie.ex @@ -1,9 +1,7 @@ -defmodule FlixWeb.Graphql.Types.Movie do +defmodule FlixWeb.GraphQL.Types.Movie do use Absinthe.Schema.Notation - import_types(Absinthe.Type.Custom) - - alias FlixWeb.Graphql.Resolvers + alias FlixWeb.GraphQL.Resolvers @desc "a movie" object :movie do diff --git a/lib/flix_web/graphql/types/review.ex b/lib/flix_web/graphql/types/review.ex index d4e99ad..0129ff1 100644 --- a/lib/flix_web/graphql/types/review.ex +++ b/lib/flix_web/graphql/types/review.ex @@ -1,4 +1,4 @@ -defmodule FlixWeb.Graphql.Types.Review do +defmodule FlixWeb.GraphQL.Types.Review do use Absinthe.Schema.Notation @desc "a review" diff --git a/lib/flix_web/graphql/types/session.ex b/lib/flix_web/graphql/types/session.ex new file mode 100644 index 0000000..4df7ac4 --- /dev/null +++ b/lib/flix_web/graphql/types/session.ex @@ -0,0 +1,8 @@ +defmodule FlixWeb.GraphQL.Types.Session do + use Absinthe.Schema.Notation + + object :session do + field :user, non_null(:user) + field :token, non_null(:string) + end +end diff --git a/lib/flix_web/graphql/types/user.ex b/lib/flix_web/graphql/types/user.ex index e659539..1ee7c15 100644 --- a/lib/flix_web/graphql/types/user.ex +++ b/lib/flix_web/graphql/types/user.ex @@ -1,4 +1,4 @@ -defmodule FlixWeb.Graphql.Types.User do +defmodule FlixWeb.GraphQL.Types.User do use Absinthe.Schema.Notation alias Flix.Accounts.User diff --git a/lib/flix_web/plugs/set_current_user.ex b/lib/flix_web/plugs/set_current_user.ex new file mode 100644 index 0000000..c9c9fd2 --- /dev/null +++ b/lib/flix_web/plugs/set_current_user.ex @@ -0,0 +1,32 @@ +# Adds an Absinthe execution context to the Phoenix connection. +# If a valid auth token is in the request header, the corresponding +# user is added to the context which is then available to all +# resolvers. Otherwise, the context is empty. +# +# This plug runs prior to `Absinthe.Plug` in the `:api` router +# so that the context is set up and `Absinthe.Plug` can extract +# the context from the connection. + +defmodule FlixWeb.Plugs.SetCurrentUser do + @behaviour Plug + + import Plug.Conn + + alias Flix.Accounts + + def init(opts), do: opts + + def call(conn, _) do + context = build_context(conn) + Absinthe.Plug.put_options(conn, context: context) + end + + defp build_context(conn) do + with ["Bearer " <> token] <- get_req_header(conn, "authorization"), + {:ok, user} <- Accounts.get_user_by_session_token(token) do + %{current_user: user} + else + _ -> %{} + end + end +end diff --git a/lib/flix_web/router.ex b/lib/flix_web/router.ex index 1036926..7309af0 100644 --- a/lib/flix_web/router.ex +++ b/lib/flix_web/router.ex @@ -14,6 +14,7 @@ defmodule FlixWeb.Router do pipeline :api do plug :accepts, ["json"] + plug FlixWeb.Plugs.SetCurrentUser end scope "/" do @@ -22,14 +23,14 @@ defmodule FlixWeb.Router do if Mix.env() in [:dev, :test] do forward "/graphiql", Absinthe.Plug.GraphiQL, - schema: FlixWeb.Graphql.Schema, - json_codec: Jason, - interface: :playground + schema: FlixWeb.GraphQL.Schema, + socket: FlixWeb.Channels.UserSocket, + json_codec: Jason end - forward "/graphql", + forward "/api", Absinthe.Plug, - schema: FlixWeb.Graphql.Schema + schema: FlixWeb.GraphQL.Schema end scope "/", FlixWeb do diff --git a/mix.exs b/mix.exs index 3ea9c9b..099d92c 100644 --- a/mix.exs +++ b/mix.exs @@ -26,6 +26,7 @@ defmodule Flix.MixProject do # Specifies which paths to compile per environment. defp elixirc_paths(:test), do: ["lib", "test/support"] + defp elixirc_paths(:dev), do: ["lib", "dev/support"] defp elixirc_paths(_), do: ["lib"] # Specifies your project dependencies. @@ -46,9 +47,10 @@ defmodule Flix.MixProject do {:telemetry_metrics, "~> 0.6.1"}, {:telemetry_poller, "~> 1.0"}, {:gettext, "~> 0.18.2"}, - {:jason, "~> 1.2.2"}, + {:jason, "~> 1.3.0"}, {:plug_cowboy, "~> 2.5.2"}, {:absinthe_plug, "~> 1.5.8"}, + {:absinthe_phoenix, "~> 2.0.2"}, {:cors_plug, "~> 2.0.3"}, {:bcrypt_elixir, "~> 2.0"}, {:number, "~> 1.0"}, diff --git a/mix.lock b/mix.lock index 25ad428..cd9be1a 100644 --- a/mix.lock +++ b/mix.lock @@ -1,5 +1,6 @@ %{ "absinthe": {:hex, :absinthe, "1.7.0", "36819e7b1fd5046c9c734f27fe7e564aed3bda59f0354c37cd2df88fd32dd014", [:mix], [{:dataloader, "~> 1.0.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0 or ~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "566a5b5519afc9b29c4d367f0c6768162de3ec03e9bf9916f9dc2bcbe7c09643"}, + "absinthe_phoenix": {:hex, :absinthe_phoenix, "2.0.2", "e607b438db900049b9b3760f8ecd0591017a46122fffed7057bf6989020992b5", [:mix], [{:absinthe, "~> 1.5", [hex: :absinthe, repo: "hexpm", optional: false]}, {:absinthe_plug, "~> 1.5", [hex: :absinthe_plug, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.5", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.13 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}], "hexpm", "d36918925c380dc7d2ed7d039c9a3b4182ec36723f7417a68745ade5aab22f8d"}, "absinthe_plug": {:hex, :absinthe_plug, "1.5.8", "38d230641ba9dca8f72f1fed2dfc8abd53b3907d1996363da32434ab6ee5d6ab", [:mix], [{:absinthe, "~> 1.5", [hex: :absinthe, repo: "hexpm", optional: false]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bbb04176647b735828861e7b2705465e53e2cf54ccf5a73ddd1ebd855f996e5a"}, "bamboo": {:hex, :bamboo, "2.1.0", "3c58f862efd74fa8c8d48a410ac592b41f7d24785e828566f7a0af549269ddc3", [:mix], [{:hackney, ">= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.4", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "f0ad2623b9a1d2dc06dcf289b59df9ebc522f49f3a21971ec87a8fce04e6d33e"}, "bamboo_phoenix": {:hex, :bamboo_phoenix, "1.0.0", "f3cc591ffb163ed0bf935d256f1f4645cd870cf436545601215745fb9cc9953f", [:mix], [{:bamboo, ">= 2.0.0", [hex: :bamboo, repo: "hexpm", optional: false]}, {:phoenix, ">= 1.3.0", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "6db88fbb26019c84a47994bb2bd879c0887c29ce6c559bc6385fd54eb8b37dee"}, @@ -30,7 +31,7 @@ "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, "html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"}, "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, - "jason": {:hex, :jason, "1.2.2", "ba43e3f2709fd1aa1dce90aaabfd039d000469c05c56f0b8e31978e03fa39052", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "18a228f5f0058ee183f29f9eae0805c6e59d61c3b006760668d8d18ff0d12179"}, + "jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, From 661d341aa72da44ec1c81fee33a87e729a3df1e8 Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Thu, 7 Apr 2022 12:20:36 -0700 Subject: [PATCH 4/6] DC: Upgrade software requirements. (#116) --- .tool-versions | 2 +- README.md | 2 +- mix.exs | 14 ++++++++++---- mix.lock | 1 + phoenix_static_buildpack.config | 2 +- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/.tool-versions b/.tool-versions index 85f8b33..057df26 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ erlang 24.3.2 -elixir 1.13.3-otp-24 +elixir 1.13.4-otp-24 diff --git a/README.md b/README.md index 5be49e9..5b8049b 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ The purpose of this project is to implement an application where fans can commen - Erlang 24.3.2 or newer -- Node >= 14.19.0 and <= 15.0 +- Node >= 14.19.1 and <= 15.0 - Phoenix 1.6.6 or newer diff --git a/mix.exs b/mix.exs index 099d92c..d968f6b 100644 --- a/mix.exs +++ b/mix.exs @@ -5,7 +5,7 @@ defmodule Flix.MixProject do [ app: :flix, version: "0.1.0", - elixir: "~> 1.13.3", + elixir: "~> 1.13.4", elixirc_paths: elixirc_paths(Mix.env()), compilers: [:gettext] ++ Mix.compilers(), start_permanent: Mix.env() == :prod, @@ -20,7 +20,12 @@ defmodule Flix.MixProject do def application do [ mod: {Flix.Application, []}, - extra_applications: [:logger, :runtime_tools, :phoenix_html_simplified_helpers] + extra_applications: [ + :ex_machina, + :logger, + :runtime_tools, + :phoenix_html_simplified_helpers + ] ] end @@ -65,9 +70,10 @@ defmodule Flix.MixProject do {:ex_parameterize, "~> 1.0"}, {:bamboo, "~> 2.1.0"}, {:bamboo_phoenix, "~> 1.0"}, - {:credo, "~> 1.5", only: [:dev, :test], runtime: false} + {:credo, "~> 1.5", only: [:dev, :test], runtime: false}, # , - # {:mix_test_watch, "~> 1.1"} + # {:mix_test_watch, "~> 1.1"}, + {:ex_machina, "~> 2.7.0", only: :test} ] end diff --git a/mix.lock b/mix.lock index cd9be1a..56bed2e 100644 --- a/mix.lock +++ b/mix.lock @@ -24,6 +24,7 @@ "esbuild": {:hex, :esbuild, "0.4.0", "9f17db148aead4cf1e6e6a584214357287a93407b5fb51a031f122b61385d4c2", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "b61e4e6b92ffe45e4ee4755a22de6211a67c67987dc02afb35a425a0add1d447"}, "ex_aws": {:hex, :ex_aws, "2.1.9", "dc4865ecc20a05190a34a0ac5213e3e5e2b0a75a0c2835e923ae7bfeac5e3c31", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "3e6c776703c9076001fbe1f7c049535f042cb2afa0d2cbd3b47cbc4e92ac0d10"}, "ex_aws_s3": {:hex, :ex_aws_s3, "2.3.2", "92a63b72d763b488510626d528775b26831f5c82b066a63a3128054b7a09de28", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "b235b27131409bcc293c343bf39f1fbdd32892aa237b3f13752e914dc2979960"}, + "ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"}, "ex_parameterize": {:hex, :ex_parameterize, "1.0.0", "03153ce953872886c21f7fca89e1416ad05d96c4def5c684136ecb418e49dc23", [:mix], [], "hexpm", "24fea3625bf3fbe1ffda0136738ac73b92070cffea312709a538410db0b10448"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, "floki": {:hex, :floki, "0.32.0", "f915dc15258bc997d49be1f5ef7d3992f8834d6f5695270acad17b41f5bcc8e2", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "1c5a91cae1fd8931c26a4826b5e2372c284813904c8bacb468b5de39c7ececbd"}, diff --git a/phoenix_static_buildpack.config b/phoenix_static_buildpack.config index 3359867..b2cb3d0 100644 --- a/phoenix_static_buildpack.config +++ b/phoenix_static_buildpack.config @@ -1,2 +1,2 @@ # Node.js version -node_version=14.19.0 +node_version=14.19.1 From b08080a504bd8ce380e992a8b094c2632689bd0f Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Mon, 18 Apr 2022 23:00:02 -0700 Subject: [PATCH 5/6] Fix ExMachina and TestWatch configuration . (#118) --- .tool-versions | 2 +- config/config.exs | 18 +++++++++--------- elixir_buildpack.config | 4 ++-- mix.exs | 15 ++++++++------- mix.lock | 16 ++++++++-------- test/test_helper.exs | 1 + 6 files changed, 29 insertions(+), 27 deletions(-) diff --git a/.tool-versions b/.tool-versions index 057df26..6b61424 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -erlang 24.3.2 +erlang 24.3.3 elixir 1.13.4-otp-24 diff --git a/config/config.exs b/config/config.exs index 03cc928..791e0ce 100644 --- a/config/config.exs +++ b/config/config.exs @@ -48,15 +48,15 @@ config :flix, Flix.Mailer, adapter: Bamboo.SendGridAdapter, api_key: System.get_env("SENDGRID_API_KEY") -# Configure mix_test_watch -# if Mix.env == :dev do -# config :mix_test_watch, -# clear: true, -# tasks: [ -# "test", -# "credo", -# ] -# end +# Configure Mix Test Watch +if Mix.env == :dev do + config :mix_test_watch, + clear: true, + tasks: [ + "test", + "credo" + ] +end # Configure Absinthe SDL/JSON code generation. # config :absinthe, diff --git a/elixir_buildpack.config b/elixir_buildpack.config index 0a901d4..a0d1275 100644 --- a/elixir_buildpack.config +++ b/elixir_buildpack.config @@ -1,5 +1,5 @@ # Elixir version -elixir_version=1.13.3 +elixir_version=1.13.4 # Erlang version -erlang_version=24.3.2 +erlang_version=24.3.3 diff --git a/mix.exs b/mix.exs index d968f6b..7acb335 100644 --- a/mix.exs +++ b/mix.exs @@ -10,7 +10,10 @@ defmodule Flix.MixProject do compilers: [:gettext] ++ Mix.compilers(), start_permanent: Mix.env() == :prod, aliases: aliases(), - deps: deps() + deps: deps(), + preferred_cli_env: [ + "test.watch": :test + ] ] end @@ -21,10 +24,9 @@ defmodule Flix.MixProject do [ mod: {Flix.Application, []}, extra_applications: [ - :ex_machina, :logger, - :runtime_tools, - :phoenix_html_simplified_helpers + :phoenix_html_simplified_helpers, + :runtime_tools ] ] end @@ -70,9 +72,8 @@ defmodule Flix.MixProject do {:ex_parameterize, "~> 1.0"}, {:bamboo, "~> 2.1.0"}, {:bamboo_phoenix, "~> 1.0"}, - {:credo, "~> 1.5", only: [:dev, :test], runtime: false}, - # , - # {:mix_test_watch, "~> 1.1"}, + {:credo, "~> 1.6.4", only: [:dev, :test], runtime: false}, + {:mix_test_watch, "~> 1.1.0", only: [:dev, :test], runtime: false}, {:ex_machina, "~> 2.7.0", only: :test} ] end diff --git a/mix.lock b/mix.lock index 56bed2e..3dc2222 100644 --- a/mix.lock +++ b/mix.lock @@ -27,7 +27,7 @@ "ex_machina": {:hex, :ex_machina, "2.7.0", "b792cc3127fd0680fecdb6299235b4727a4944a09ff0fa904cc639272cd92dc7", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "419aa7a39bde11894c87a615c4ecaa52d8f107bbdd81d810465186f783245bf8"}, "ex_parameterize": {:hex, :ex_parameterize, "1.0.0", "03153ce953872886c21f7fca89e1416ad05d96c4def5c684136ecb418e49dc23", [:mix], [], "hexpm", "24fea3625bf3fbe1ffda0136738ac73b92070cffea312709a538410db0b10448"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, - "floki": {:hex, :floki, "0.32.0", "f915dc15258bc997d49be1f5ef7d3992f8834d6f5695270acad17b41f5bcc8e2", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "1c5a91cae1fd8931c26a4826b5e2372c284813904c8bacb468b5de39c7ececbd"}, + "floki": {:hex, :floki, "0.32.1", "dfe3b8db3b793939c264e6f785bca01753d17318d144bd44b407fb3493acaa87", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "d4b91c713e4a784a3f7b1e3cc016eefc619f6b1c3898464222867cafd3c681a3"}, "gettext": {:hex, :gettext, "0.18.2", "7df3ea191bb56c0309c00a783334b288d08a879f53a7014341284635850a6e55", [:mix], [], "hexpm", "f9f537b13d4fdd30f3039d33cb80144c3aa1f8d9698e47d7bcbcc8df93b1f5c5"}, "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, "html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"}, @@ -40,25 +40,25 @@ "nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"}, "number": {:hex, :number, "1.0.3", "932c8a2d478a181c624138958ca88a78070332191b8061717270d939778c9857", [:mix], [{:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "dd397bbc096b2ca965a6a430126cc9cf7b9ef7421130def69bcf572232ca0f18"}, "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, - "phoenix": {:hex, :phoenix, "1.6.6", "281c8ce8dccc9f60607346b72cdfc597c3dde134dd9df28dff08282f0b751754", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "807bd646e64cd9dc83db016199715faba72758e6db1de0707eef0a2da4924364"}, + "phoenix": {:hex, :phoenix, "1.6.7", "f1de32418bbbcd471f4fe74d3860ee9c8e8c6c36a0ec173be8ff468a5d72ac90", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b354a4f11d9a2f3a380fb731042dae064f22d7aed8c7e7c024a2459f12994aad"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"}, "phoenix_html": {:hex, :phoenix_html, "3.2.0", "1c1219d4b6cb22ac72f12f73dc5fad6c7563104d083f711c3fcd8551a1f4ae11", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "36ec97ba56d25c0136ef1992c37957e4246b649d620958a1f9fa86165f8bc54f"}, "phoenix_html_simplified_helpers": {:hex, :phoenix_html_simplified_helpers, "2.1.0", "252c80df9a5bf8c8312b8fff57bc9735fcc07c599a2e825967d8b919b89a1eae", [:mix], [{:ecto, "~> 3.0 or ~> 2.2 or ~> 2.1", [hex: :ecto, repo: "hexpm", optional: false]}, {:gettext, ">= 0.11.0", [hex: :gettext, repo: "hexpm", optional: false]}, {:timex, "~> 3.4 or ~> 3.3 or ~> 3.2", [hex: :timex, repo: "hexpm", optional: false]}], "hexpm", "5444ec916abfaa72e38fd57974d7ceb18a08433bbfc2c1094f0a5a5064c03165"}, "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.5", "1495bb014be12c9a9252eca04b9af54246f6b5c1e4cd1f30210cd00ec540cf8e", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.7", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "ef4fa50dd78364409039c99cf6f98ab5209b4c5f8796c17f4db118324f0db852"}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.3.3", "3a53772a6118d5679bf50fc1670505a290e32a1d195df9e069d8c53ab040c054", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "766796676e5f558dbae5d1bdb066849673e956005e3730dfd5affd7a6da4abac"}, - "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.7", "05a42377075868a678d446361effba80cefef19ab98941c01a7a4c7560b29121", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.5.9 or ~> 1.6.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "25eaf41028eb351b90d4f69671874643a09944098fefd0d01d442f40a6091b6f"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.9", "36b5aa812bc3ccd64c9630f6b3234d9ea21105493237e927aae19d0ba758f0db", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f7ebc3e0ba0c5f6b6996ed6c901ddbfdaba59a6d09b569e7cb2f2f7d693b4455"}, "phoenix_mtm": {:git, "https://github.com/adam12/phoenix_mtm", "4f508e3fdd427e6cf1271c8e0f78dbdb90bb6a9b", []}, - "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"}, + "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"}, "phoenix_view": {:hex, :phoenix_view, "1.1.2", "1b82764a065fb41051637872c7bd07ed2fdb6f5c3bd89684d4dca6e10115c95a", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "7ae90ad27b09091266f6adbb61e1d2516a7c3d7062c6789d46a7554ec40f3a56"}, - "plug": {:hex, :plug, "1.13.4", "addb6e125347226e3b11489e23d22a60f7ab74786befb86c14f94fb5f23ca9a4", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "06114c1f2a334212fe3ae567dbb3b1d29fd492c1a09783d52f3d489c1a6f4cf2"}, + "plug": {:hex, :plug, "1.13.6", "187beb6b67c6cec50503e940f0434ea4692b19384d47e5fdfd701e93cadb4cc2", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "02b9c6b9955bce92c829f31d6284bf53c591ca63c4fb9ff81dfd0418667a34ff"}, "plug_cowboy": {:hex, :plug_cowboy, "2.5.2", "62894ccd601cf9597e2c23911ff12798a8a18d237e9739f58a6b04e4988899fe", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ea6e87f774c8608d60c8d34022a7d073bd7680a0a013f049fc62bf35efea1044"}, "plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"}, "postgrex": {:hex, :postgrex, "0.15.13", "7794e697481799aee8982688c261901de493eb64451feee6ea58207d7266d54a", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "3ffb76e1a97cfefe5c6a95632a27ffb67f28871c9741fb585f9d1c3cd2af70f1"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, - "sweet_xml": {:hex, :sweet_xml, "0.7.2", "4729f997286811fabdd8288f8474e0840a76573051062f066c4b597e76f14f9f", [:mix], [], "hexpm", "6894e68a120f454534d99045ea3325f7740ea71260bc315f82e29731d570a6e8"}, - "swoosh": {:hex, :swoosh, "1.6.3", "598d3f07641004bedb3eede40057760ae18be1073cff72f079ca1e1fc9cd97b9", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "81ff9d7c7c4005a57465a7eb712edd71db51829aef94c8a34c30c5b9e9964adf"}, - "telemetry": {:hex, :telemetry, "1.0.0", "0f453a102cdf13d506b7c0ab158324c337c41f1cc7548f0bc0e130bbf0ae9452", [:rebar3], [], "hexpm", "73bc09fa59b4a0284efb4624335583c528e07ec9ae76aca96ea0673850aec57a"}, + "sweet_xml": {:hex, :sweet_xml, "0.7.3", "debb256781c75ff6a8c5cbf7981146312b66f044a2898f453709a53e5031b45b", [:mix], [], "hexpm", "e110c867a1b3fe74bfc7dd9893aa851f0eed5518d0d7cad76d7baafd30e4f5ba"}, + "swoosh": {:hex, :swoosh, "1.6.4", "ce3a4bf3e5276fd114178ebc5ed072ee0c177a7b3a09e5992aa005778ac143c2", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad4c8b534812433730b6241a1d9df38b1da75fdfa340f51887a31d7e9343fffe"}, + "telemetry": {:hex, :telemetry, "1.1.0", "a589817034a27eab11144ad24d5c0f9fab1f58173274b1e9bae7074af9cbee51", [:rebar3], [], "hexpm", "b727b2a1f75614774cff2d7565b64d0dfa5bd52ba517f16543e6fc7efcc0df48"}, "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"}, "telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"}, "timex": {:hex, :timex, "3.7.7", "3ed093cae596a410759104d878ad7b38e78b7c2151c6190340835515d4a46b8a", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 1.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "0ec4b09f25fe311321f9fc04144a7e3affe48eb29481d7a5583849b6c4dfa0a7"}, diff --git a/test/test_helper.exs b/test/test_helper.exs index a7d55e5..dff698f 100644 --- a/test/test_helper.exs +++ b/test/test_helper.exs @@ -1,2 +1,3 @@ ExUnit.start() Ecto.Adapters.SQL.Sandbox.mode(Flix.Repo, :manual) +{:ok, _} = Application.ensure_all_started(:ex_machina) From 22de32471edfdc21c96760d77d257837d594303a Mon Sep 17 00:00:00 2001 From: Conrad Taylor Date: Sun, 24 Apr 2022 22:46:05 -0700 Subject: [PATCH 6/6] Add session sign in test. (#119) --- lib/flix/accounts.ex | 5 +- lib/flix/catalogs.ex | 2 - lib/flix_web/auth_token.ex | 21 +++++++++ lib/flix_web/graphql/resolvers/accounts.ex | 4 +- .../schemas/mutations/accounts_test.exs | 46 +++++++++++++++++++ test/support/factory.ex | 27 +++++++++++ 6 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 lib/flix_web/auth_token.ex create mode 100644 test/flix_web/graphql/schemas/mutations/accounts_test.exs create mode 100644 test/support/factory.ex diff --git a/lib/flix/accounts.ex b/lib/flix/accounts.ex index 4e7d923..1658590 100644 --- a/lib/flix/accounts.ex +++ b/lib/flix/accounts.ex @@ -74,9 +74,8 @@ defmodule Flix.Accounts do def authenticate(email, password) when is_binary(email) and is_binary(password) do - user = Repo.get_by(User, email: email) - - with true <- User.valid_password?(user, password) do + with user <- Repo.get_by(User, email: email), + true <- User.valid_password?(user, password) do {:ok, user} else _ -> :error diff --git a/lib/flix/catalogs.ex b/lib/flix/catalogs.ex index 652a6ca..6cc8e69 100644 --- a/lib/flix/catalogs.ex +++ b/lib/flix/catalogs.ex @@ -203,8 +203,6 @@ defmodule Flix.Catalogs do """ def create_review(attrs \\ %{}) do - IO.inspect(attrs, label: "create_review") - %Review{} |> Review.changeset(attrs) |> Repo.insert() diff --git a/lib/flix_web/auth_token.ex b/lib/flix_web/auth_token.ex new file mode 100644 index 0000000..260fe9e --- /dev/null +++ b/lib/flix_web/auth_token.ex @@ -0,0 +1,21 @@ +defmodule FlixWeb.AuthToken do + @user_salt "user auth salt" + + @doc """ + Encodes the given `user` id and signs it, returning a token + clients can use as identification when using the API. + """ + def sign(user) do + Phoenix.Token.sign(FlixWeb.Endpoint, @user_salt, %{id: user.id}) + end + + @doc """ + Decodes the original data from the given `token` and + verifies its integrity. + """ + def verify(token) do + Phoenix.Token.verify(FlixWeb.Endpoint, @user_salt, token, [ + max_age: 365 * 24 * 3600 + ]) + end +end diff --git a/lib/flix_web/graphql/resolvers/accounts.ex b/lib/flix_web/graphql/resolvers/accounts.ex index 5cb15ad..77b148a 100644 --- a/lib/flix_web/graphql/resolvers/accounts.ex +++ b/lib/flix_web/graphql/resolvers/accounts.ex @@ -8,7 +8,7 @@ defmodule FlixWeb.GraphQL.Resolvers.Accounts do {:error, "Whoops, invalid credentials!"} {:ok, user} -> - token = Accounts.generate_user_session_token(user) + token = FlixWeb.AuthToken.sign(user) {:ok, %{user: user, token: token}} end end @@ -23,7 +23,7 @@ defmodule FlixWeb.GraphQL.Resolvers.Accounts do } {:ok, user} -> - token = Accounts.generate_user_session_token(user) + token = FlixWeb.AuthToken.sign(user) {:ok, %{user: user, token: token}} end end diff --git a/test/flix_web/graphql/schemas/mutations/accounts_test.exs b/test/flix_web/graphql/schemas/mutations/accounts_test.exs new file mode 100644 index 0000000..8e0b60a --- /dev/null +++ b/test/flix_web/graphql/schemas/mutations/accounts_test.exs @@ -0,0 +1,46 @@ +defmodule FlixWeb.GraphQL.Schemas.Mutations.AccountsTest do + use FlixWeb.ConnCase, async: true + + alias Flix.Support.Factory + + describe "new session with valid arguments" do + test "create session" do + user = Factory.create_user() + + operation = """ + mutation Signin($email: String!) { + signin( + email: $email, + password: "1qaz2wsx3edc" + ) + { + token + user { + id + email + } + } + } + """ + + response = + post( + build_conn(), + "/api", + query: operation, + variables: %{"email" => user.email} + ) + + assert %{ + "data" => %{ + "signin" => %{ + "token" => token, + "user" => _user_data + } + } + } = json_response(response, 200) + + assert {:ok, %{id: user.id}} == FlixWeb.AuthToken.verify(token) + end + end +end diff --git a/test/support/factory.ex b/test/support/factory.ex new file mode 100644 index 0000000..26d512a --- /dev/null +++ b/test/support/factory.ex @@ -0,0 +1,27 @@ +defmodule Flix.Support.Factory do + use ExMachina.Ecto, repo: Flix.Repo + + alias Flix.Accounts + alias Flix.Accounts.User + alias Flix.Accounts.UserToken + + def create_user() do + int = :erlang.unique_integer([:positive, :monotonic]) + + params = %{ + name: "User #{int}", + email: sequence(:email, &"email#{&1}@example.com"), + password: "1qaz2wsx3edc", + password_confirmation: "1qaz2wsx3edc", + username: sequence(:username, &"username#{&1}") + } + + {:ok, user} = Accounts.register_user(params) + + Ecto.Multi.new() + |> Ecto.Multi.update(:user, User.confirm_changeset(user)) + |> Ecto.Multi.delete_all(:tokens, UserToken.user_and_contexts_query(user, ["confirm"])) + + user + end +end