From b17eee4cdd6f289f1f0a26050e7c0ea30c453cca Mon Sep 17 00:00:00 2001 From: Muhammad Rafif Elfazri <rafif.elfazri@gmail.com> Date: Sat, 20 Feb 2021 10:37:14 +0700 Subject: [PATCH 1/3] Remove Funpro expalnation and add deploy information --- README.md | 70 ++++++++++++++++++++++--------------------------------- 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 7f5d9fa..af64a6f 100644 --- a/README.md +++ b/README.md @@ -6,60 +6,46 @@ Diskuy adalah sebuah aplikasi forum berbasis web. Thread-thread diskusi dengan t -## Penerapan Functional Programming - -#### Pure Function - -Pure Function adalah sebuah konsep dimana fungsi yang hanya bergantung pada argumen yang diberikan sehingga jika argumen yang sama diberikan, maka fungsi tersebut akan mengembalikan nilai yang sama dari sebelumnya. Fungsi ini tidak dipengaruhi oleh variabel-variabel di luar argumen dan tidak memutasi variabel apapun. -Contoh Penerapan: - -https://gitlab.cs.ui.ac.id/functional-programming/diskuy/-/commit/c80fdf947fe00a75307436dbbc5c2f363b1adb8a#9218b17cba7ad37fdc17de1e228661cc4554b811 - -File yang highlight adalah guardian.ex dan fungsi yang saya highlight adalah fungsi validate_password yang menerima password dan encrypted_password. Fungsi ini hanya memeriksa apakah argumen password dan encrypted_password sama sehingga tidak membutuhkan variabel lain selain dua argumen dan fungsi tersebut konsisten memetakan dari argumen-argumen fungsi tersebut ke satu nilai. - -#### Higher Order Function (Map) + Partially Applied Function + Pure FunctionHigher - -Order function adalah sebuah konsep dimana sebuah fungsi menerima atau mengembalikan suatu fungsi. Higher order function yang saya gunakan adalah Map yang memetakan setiap elemen dari data enumerable ke dengan argumen fungsi yang diberikan.Argumen fungsi yang diberikan menggunakan konsep ke dalam fungsi map menggunakan partially applied function, yaitu sebuah fungsi yang saat diaplikasikan tidak memerlukan argumen penuh, fungsi tersebut dapat menerima secara terpisah. -Contoh penerapan: - -https://gitlab.cs.ui.ac.id/functional-programming/diskuy/-/blob/master/diskuy_back/lib/diskuy/utility/utility.ex - -Fungsi yang saya highlight dari file ini adalah fungsi capitalize_string yang menerima input text yang berupa string. Fungsi ini mengkapitalisasi setiap huruf pertama dari suatu kata dalam string tersebut. Fungsi tersebut menggunakan melakukan split pada text dengan dengan delimiter single white space yang menghasilkan **list of string** dan kemudian dengan hasil tersebut dimasukkan ke dalam fungsi Enum.map_join (Fungsi yang melakukan map dan melakukan konkantenasi elemen map dengan delimiter tertentu) sebagai argumen pertama, argumen kedua whitespace “ “, dan argumen ketiga fungsi String.capitalize/1 yang diubah menjadi partial function dengan & operator pada fungsi tersebut yang menyebabkan fungsi tidak perlu diaplikasikan dengan argumen penuh / dapat menunggu argumen. Fungsi ini juga merupakan pure function karena hanya membutuhkan argumen fungsi dan tidak mengubah variabel apapun. - -#### Pattern Matching - -Pattern Matching adalah sebuah konsep functional programming dimana kita dapat mendefinisikan fungsi dengan beberapa pattern argumen yang dimana setiap pattern argumen memiliki function body yang dapat memiliki behaviour yang berbeda satu sama lain. - -Contoh Penerapan Pattern Matching: +## Cara Menjalankan Aplikasi (Development) +Cara menyalakan server Phoenix untuk aplikasi ini : -https://gitlab.cs.ui.ac.id/functional-programming/diskuy/-/blob/master/diskuy_back/lib/diskuy_web/views/user_view.ex + * Install dependencies dengan `mix deps.get` + * Setup file ```config/dev.exs``` dan isi credential username dan password user pada database postgresql. + * Buat dan lakukan migrate pada database dengan `mix ecto.setup` + * Nyalakan server Phoenix dengan `mix phx.server` -Pattern matching yang dilakukan diatas adlah pattern matching pada pada argumen pertama dari fungsi render yang body dari functionnya memiliki behaviour yang berbeda-beda dalam men-serialize suatu struct menjadi JSON. +Sekarang anda bisa mengakses [`localhost:4000`](http://localhost:4000) dari browser anda. -##### Pipe Operator +Sudah ready untuk dijalankan di production? Mohon [lihat deployment guide berikut ini](https://hexdocs.pm/phoenix/deployment.html). -Pipe Operator adalah sebuah konsep dimana hasil dari suatu fungsi dapat diberikan ke fungsi yang lain yang dihubungkan dengan pipe operator. Pipe operator sangat mirip sekali dengan function composition, yang membedakannya urutan menjalankan fungsi. Pipe operator menjalankan fungsi dari yang pertama didefinisikan (dari kiri ke kanan) sedangkan function composition menjalankan fungsi dari yang terakhir didefinisikan (dari kanan ke kiri). -Contoh Penerapan Pipe Operator: +## Build Production Docker Image -https://gitlab.cs.ui.ac.id/functional-programming/diskuy/-/blob/master/diskuy_back/lib/diskuy/account.ex +1. Build Image dengan perintah berikujt -Lambang pipe operator pada programming language yang saya gunakan, elixir adalah “|>” dan Pipe operator pada elixir akan mengambil mengisi argumen pertama dari sebuah fungsi yang diteruskan menggunakan pipe operator. + ```docker build -t diskuy_backend .``` -Pipe operator tersebut akan ditulis menjadi user |> User.changeset(attrs) |> Repo.update() yang ekuivalen dengan Repo.update(User.changeset(user, attrs)). Dapat dilihat bahwa pipe operator membuat kode tersebut menjadi lebih readable +### Deploy Production +1. Build Docker image sesuai dengan perintah Build DockerImage diatas +2. Isi Environment Variable pada ``` config/docker.env``` sesuai dengan Environtment yang sudah disediakan. -## Cara Menjalankan Aplikasi -Cara menyalakan server Phoenix untuk aplikasi ini : + ```shell + SECRET_KEY_BASE=REALLY_LONG_SECRET + GUARDIAN_SECRET_KEY_BASE=REALLY_LONG_SECRET + DATABASE_HOST=db + DATABASE_URL=ecto://postgres:postgres@db/postgres + PORT=4000 + HOSTNAME=localhost + POSTGRES_PASSWORD=postgres + LANG=en_US.UTF-8s + ``` - * Install dependencies dengan `mix deps.get` - * Setup file ```config/dev.exs``` dan isi credential username dan password user pada database postgresql. - * Buat dan lakukan migrate pada database dengan `mix ecto.setup` - * Nyalakan server Phoenix dengan `mix phx.server` +3. Jalankan command ```docker-compose up``` untuk mendeploy Backend server. -Sekarang anda bisa mengakses [`localhost:4000`](http://localhost:4000) dari browser anda. +4. Backend server dapat diakses pada http://localshost -Sudah ready untuk dijalankan di production? Mohon [lihat deployment guide berikut ini](https://hexdocs.pm/phoenix/deployment.html). +5. Jalankan command ```docker-compose down``` untuk menghentikan server ## Pelajari lebih lanjut @@ -74,7 +60,7 @@ Kelompok 18 * Fadhil Pradipta - 1806205344 * Jonathan - 1806204985 - * Muhammad Rafif ELfazri- 1806205722 + * Muhammad Rafif Elfazri- 1806205722 * Ryo Axton Lie - 1806205571 ## Acknowledgements -- GitLab From cb5c8cff14a8439d50ff90a354aef9a33448043b Mon Sep 17 00:00:00 2001 From: Muhammad Rafif Elfazri <rafif.elfazri@gmail.com> Date: Sat, 20 Feb 2021 10:40:23 +0700 Subject: [PATCH 2/3] Add details to generate-several ENV variables --- README.md | 4 ++-- config/docker.env | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index af64a6f..4303bb2 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,8 @@ Sudah ready untuk dijalankan di production? Mohon [lihat deployment guide beriku 2. Isi Environment Variable pada ``` config/docker.env``` sesuai dengan Environtment yang sudah disediakan. ```shell - SECRET_KEY_BASE=REALLY_LONG_SECRET - GUARDIAN_SECRET_KEY_BASE=REALLY_LONG_SECRET + SECRET_KEY_BASE=REALLY_LONG_SECRET ## Generate it with "mix phx.gen.secret" + GUARDIAN_SECRET_KEY_BASE=REALLY_LONG_SECRET ## Generate it with "guardian phx.gen.secret" DATABASE_HOST=db DATABASE_URL=ecto://postgres:postgres@db/postgres PORT=4000 diff --git a/config/docker.env b/config/docker.env index 86d0150..bf73f81 100644 --- a/config/docker.env +++ b/config/docker.env @@ -1,5 +1,5 @@ -SECRET_KEY_BASE=REALLY_LONG_SECRET -GUARDIAN_SECRET_KEY_BASE=REALLY_LONG_SECRET +SECRET_KEY_BASE=REALLY_LONG_SECRET ## Generate it with "mix phx.gen.secret" +GUARDIAN_SECRET_KEY_BASE=REALLY_LONG_SECRET ## Generate it with "guardian phx.gen.secret" DATABASE_HOST=db DATABASE_URL=ecto://postgres:postgres@db/postgres PORT=4000 -- GitLab From 7791b5c7126a23a4833cdf1e8860cd7ef460181c Mon Sep 17 00:00:00 2001 From: Muhammad Rafif Elfazri <rafif.elfazri@gmail.com> Date: Sat, 20 Feb 2021 17:25:11 +0700 Subject: [PATCH 3/3] Remove elixir_auth_google dependencies and create manual auth_google (Production issue) --- lib/diskuy_web/auth/google_auth.ex | 39 ++++++++++++++++++++++++------ mix.exs | 3 ++- mix.lock | 2 +- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/lib/diskuy_web/auth/google_auth.ex b/lib/diskuy_web/auth/google_auth.ex index 83ed14b..91d19e3 100644 --- a/lib/diskuy_web/auth/google_auth.ex +++ b/lib/diskuy_web/auth/google_auth.ex @@ -3,17 +3,40 @@ defmodule DiskuyWeb.Auth.GoogleAuth do alias Diskuy.Account alias Diskuy.Utility.Utility - def get_access_token(code, conn) do - case ElixirAuthGoogle.get_token(code, conn) do - {:ok, profile} -> - {:ok, profile} - _ -> - {:error, :bad_request} - end + @google_user_profile "https://www.googleapis.com/oauth2/v3/userinfo" + + @spec get_user_profile(String.t) :: String.t + def get_user_profile(token) do + "#{@google_user_profile}?access_token=#{token}" + |> HTTPoison.get() + |> parse_body_response() end + @spec parse_body_response({atom, String.t}) :: String.t + def parse_body_response({:error, err}), do: {:error, err} + def parse_body_response({:ok, response}) do + body = Map.get(response, :body) + if body == nil do + {:error, :no_body} + else # make keys of map atoms for easier access in templates + {:ok, str_key_map} = Poison.decode(body) + atom_key_map = for {key, val} <- str_key_map, into: %{}, + do: {String.to_atom(key), val} + {:ok, atom_key_map} + end # https://stackoverflow.com/questions/31990134 + end + + # def get_access_token(code, conn) do + # case ElixirAuthGoogle.get_token(code, conn) do + # {:ok, profile} -> + # {:ok, profile} + # _ -> + # {:error, :bad_request} + # end + # end + def create_local_token(token) do - {:ok, profile} = ElixirAuthGoogle.get_user_profile(token) + {:ok, profile} = get_user_profile(token) {email, username, picture} = {profile[:email], profile[:name], profile[:picture]} case Account.get_by_email(email) do {:ok, user} -> diff --git a/mix.exs b/mix.exs index 3abf138..cabc8e4 100644 --- a/mix.exs +++ b/mix.exs @@ -45,7 +45,8 @@ defmodule Diskuy.MixProject do {:plug_cowboy, "~> 2.0"}, {:cors_plug, "~> 2.0"}, {:poison, "~> 4.0"}, - {:elixir_auth_google, "~> 1.3.0"}, + {:httpoison, "~> 1.8"}, + # {:elixir_auth_google, "~> 1.3.0"}, # {:oauth2, "~> 2.0", override: true}, # {:ueberauth, "~> 0.6"}, # {:ueberauth_google, "~> 0.8"}, diff --git a/mix.lock b/mix.lock index 69be314..8219dc8 100644 --- a/mix.lock +++ b/mix.lock @@ -16,7 +16,7 @@ "gettext": {:hex, :gettext, "0.18.2", "7df3ea191bb56c0309c00a783334b288d08a879f53a7014341284635850a6e55", [:mix], [], "hexpm", "f9f537b13d4fdd30f3039d33cb80144c3aa1f8d9698e47d7bcbcc8df93b1f5c5"}, "guardian": {:hex, :guardian, "2.1.1", "1f02b349f6ba765647cc834036a8d76fa4bd65605342fe3a031df3c99d0d411a", [:mix], [{:jose, "~> 1.8", [hex: :jose, repo: "hexpm", optional: false]}, {:plug, "~> 1.3.3 or ~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "189b87ba7ce6b40d6ba029138098b96ffc4ae78f229f5b39539b9141af8bf0f8"}, "hackney": {:hex, :hackney, "1.17.0", "717ea195fd2f898d9fe9f1ce0afcc2621a41ecfe137fae57e7fe6e9484b9aa99", [:rebar3], [{:certifi, "~>2.5", [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", [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", "64c22225f1ea8855f584720c0e5b3cd14095703af1c9fbc845ba042811dc671c"}, - "httpoison": {:hex, :httpoison, "1.7.0", "abba7d086233c2d8574726227b6c2c4f6e53c4deae7fe5f6de531162ce9929a0", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "975cc87c845a103d3d1ea1ccfd68a2700c211a434d8428b10c323dc95dc5b980"}, + "httpoison": {:hex, :httpoison, "1.8.0", "6b85dea15820b7804ef607ff78406ab449dd78bed923a49c7160e1886e987a3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "28089eaa98cf90c66265b6b5ad87c59a3729bea2e74e9d08f9b51eb9729b3c3a"}, "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"}, "jose": {:hex, :jose, "1.11.1", "59da64010c69aad6cde2f5b9248b896b84472e99bd18f246085b7b9fe435dcdb", [:mix, :rebar3], [], "hexpm", "078f6c9fb3cd2f4cfafc972c814261a7d1e8d2b3685c0a76eb87e158efff1ac5"}, -- GitLab