Implement rudimentary API for storing and retrieving notes

This commit is contained in:
Adrian Gruntkowski 2024-11-18 22:34:38 +01:00
parent f89897f05a
commit 08e145f00a
20 changed files with 358 additions and 2 deletions

View file

@ -1,5 +1,6 @@
# Used by "mix format"
[
import_deps: [:plug],
subdirectories: ["priv/repo/migrations"],
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

2
.gitignore vendored
View file

@ -24,3 +24,5 @@ jenot-*.tar
# Temporary files, for example, from tests.
/tmp/
/priv/db_*

6
config/config.exs Normal file
View file

@ -0,0 +1,6 @@
import Config
config :jenot,
ecto_repos: [Jenot.Repo]
import_config "#{config_env()}.exs"

View file

@ -1,4 +1,8 @@
import Config
config :plug_live_reload,
patterns: [
~r"priv/static/.*(html|js|css|png|jpeg|jpg|gif|svg)$"
]
config :jenot, Jenot.Repo, database: "priv/db_dev.sqlite"

1
config/prod.exs Normal file
View file

@ -0,0 +1 @@
import Config

12
config/runtime.exs Normal file
View file

@ -0,0 +1,12 @@
import Config
config :web_push_elixir,
vapid_public_key: System.fetch_env!("VAPID_PUBLIC_KEY"),
vapid_private_key: System.fetch_env!("VAPID_PRIVATE_KEY"),
vapid_subject: System.fetch_env!("VAPID_SUBJECT")
config :jenot, Jenot.Repo, key: System.fetch_env!("EXQLITE_SECRET")
if config_env() == :prod do
config :jenot, Jenot.Repo, database: System.get_env("EXQLITE_PATH")
end

3
config/test.exs Normal file
View file

@ -0,0 +1,3 @@
import Config
config :jenot, Jenot.Repo, database: :memory

16
lib/jenot/account.ex Normal file
View file

@ -0,0 +1,16 @@
defmodule Jenot.Account do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:id, :binary_id, autogenerate: true}
schema "accounts" do
timestamps(type: :utc_datetime)
end
def new() do
%__MODULE__{}
|> change()
|> put_change(:id, Ecto.UUID.generate())
end
end

8
lib/jenot/accounts.ex Normal file
View file

@ -0,0 +1,8 @@
defmodule Jenot.Accounts do
alias Jenot.Account
alias Jenot.Repo
def get() do
Repo.one(Account)
end
end

View file

@ -6,6 +6,7 @@ defmodule Jenot.Application do
@impl true
def start(_type, _args) do
children = [
Jenot.Repo,
{Bandit, plug: Jenot.Web, scheme: :http, port: 4000}
]

29
lib/jenot/note.ex Normal file
View file

@ -0,0 +1,29 @@
defmodule Jenot.Note do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:id, :binary_id, autogenerate: true}
schema "notes" do
field(:internal_id, :string)
field(:title, :string)
field(:content, :string)
belongs_to(:account, Jenot.Account, type: :binary_id)
timestamps(type: :utc_datetime)
end
def new(account, params) do
%__MODULE__{}
|> cast(params, [:internal_id, :title, :content])
|> put_change(:id, Ecto.UUID.generate())
|> validate_required([:internal_id])
|> put_assoc(:account, account)
end
def update(note, params) do
note
|> cast(params, [:title, :content])
end
end

80
lib/jenot/notes.ex Normal file
View file

@ -0,0 +1,80 @@
defmodule Jenot.Notes do
import Ecto.Query
alias Jenot.Note
alias Jenot.Repo
def serialize(note) do
Map.take(note, [:internal_id, :title, :content, :inserted_at, :updated_at])
end
def latest_change(account) do
Note
|> where(account_id: ^account.id)
|> select([a], max(a.updated_at))
|> Repo.one()
end
def all(account, since \\ nil) do
Note
|> where(account_id: ^account.id)
|> maybe_filter_since(since)
|> Repo.all()
end
def add(account, params) do
changeset = Note.new(account, params)
case upsert(changeset, target: [:account_id, :internal_id]) do
{:ok, note} -> {:ok, note}
{:error, _changeset} -> {:error, :invalid_data}
end
end
def note_by_internal_id(account, internal_id) do
note = Repo.get_by(Note, account_id: account.id, internal_id: internal_id)
if note do
{:ok, note}
else
{:error, :note_not_found}
end
end
def update(account, internal_id, params) do
with {:ok, note} <- note_by_internal_id(account, internal_id) do
changeset = Note.update(note, params)
case upsert(changeset, target: [:id]) do
{:ok, note} -> {:ok, note}
{:error, _changeset} -> {:error, :invalid_data}
end
end
end
def delete(account, internal_id) do
Note
|> where(account_id: ^account.id, internal_id: ^internal_id)
|> Repo.delete_all()
:ok
end
defp maybe_filter_since(query, nil), do: query
defp maybe_filter_since(query, datetime) do
where(query, [n], n.updated_at > ^datetime)
end
defp upsert(changeset, opts) do
conflict_target = Keyword.fetch!(opts, :target)
title = Ecto.Changeset.get_field(changeset, :title) || ""
content = Ecto.Changeset.get_field(changeset, :content) || ""
Repo.insert(changeset,
on_conflict: [set: [title: title, content: content, updated_at: DateTime.utc_now()]],
conflict_target: conflict_target,
returning: true
)
end
end

16
lib/jenot/reminder.ex Normal file
View file

@ -0,0 +1,16 @@
defmodule Jenot.Reminder do
use Ecto.Schema
@primary_key {:id, :binary_id, autogenerate: true}
schema "reminders" do
field(:date, :date)
field(:time, :time)
field(:day_of_week, :integer)
field(:repeat_period, Ecto.Enum, values: [:day, :week, :month, :year])
field(:repeat_count, :integer)
belongs_to(:note, Jenot.Note)
timestamps(type: :utc_datetime)
end
end

3
lib/jenot/repo.ex Normal file
View file

@ -0,0 +1,3 @@
defmodule Jenot.Repo do
use Ecto.Repo, otp_app: :jenot, adapter: Ecto.Adapters.SQLite3
end

16
lib/jenot/subscription.ex Normal file
View file

@ -0,0 +1,16 @@
defmodule Jenot.Subscription do
use Ecto.Schema
@primary_key {:id, :binary_id, autogenerate: true}
schema "subscriptions" do
field(:endpoint, :string)
field(:token, :string)
field(:auth, :string)
field(:hash, :string)
belongs_to(:account, Jenot.Account)
timestamps(type: :utc_datetime)
end
end

View file

@ -5,6 +5,9 @@ defmodule Jenot.Web do
use Plug.Router
alias Jenot.Accounts
alias Jenot.Notes
if Mix.env() == :dev do
plug PlugLiveReload
end
@ -18,6 +21,11 @@ defmodule Jenot.Web do
only: ~w(img js index.html site.webmanifest style.css),
from: {:jenot, "priv/static"}
plug Plug.Parsers,
parsers: [:urlencoded, :json],
pass: ["*/*"],
json_decoder: Jason
plug :match
plug :dispatch
@ -38,6 +46,71 @@ defmodule Jenot.Web do
""")
end
get "/api/latest" do
account = Accounts.get()
send_resp(conn, 200, Jason.encode!(%{notes: Notes.latest_change(account)}))
end
get "/api/notes" do
account = Accounts.get()
notes =
account
|> Notes.all(conn.params["since"])
|> Enum.map(&Notes.serialize/1)
send_resp(conn, 200, Jason.encode!(notes))
end
post "/api/notes" do
account = Accounts.get()
case Notes.add(account, conn.params) do
{:ok, note} ->
send_resp(conn, 200, Jason.encode!(Notes.serialize(note)))
{:error, _} ->
send_resp(conn, 422, Jason.encode!(%{error: "Invalid input data"}))
end
end
put "/api/notes/:internal_id" do
account = Accounts.get()
case Notes.update(account, internal_id, conn.params) do
{:ok, note} ->
send_resp(conn, 200, Jason.encode!(Notes.serialize(note)))
{:error, :note_not_found} ->
send_resp(conn, 422, Jason.encode!(%{error: "Note does not exist"}))
{:error, :invalid_data} ->
send_resp(conn, 422, Jason.encode!(%{error: "Invalid input data"}))
end
end
delete "/api/notes/:internal_id" do
account = Accounts.get()
:ok = Notes.delete(account, internal_id)
send_resp(conn, 204, "")
end
get "/api/push/public-key" do
public_key = Application.fetch_env!(:web_push_elixir, :vapid_public_key)
send_resp(conn, 200, Jason.encode!(%{public_key: public_key}))
end
post "/api/push/subscribe" do
send_resp(conn, 200, "")
end
post "/api/push/unsubscribe" do
send_resp(conn, 200, "")
end
match _ do
send_resp(conn, 404, "not found")
end

View file

@ -23,6 +23,8 @@ defmodule Jenot.MixProject do
defp deps do
[
{:bandit, "~> 1.0"},
{:web_push_elixir, "~> 0.4.0"},
{:ecto_sqlite3, "~> 0.17"},
{:plug_live_reload, "~> 0.1.0", only: :dev}
]
end

View file

@ -1,17 +1,37 @@
%{
"bandit": {:hex, :bandit, "1.5.7", "6856b1e1df4f2b0cb3df1377eab7891bec2da6a7fd69dc78594ad3e152363a50", [:mix], [{:hpax, "~> 1.0.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "f2dd92ae87d2cbea2fa9aa1652db157b6cba6c405cb44d4f6dd87abba41371cd"},
"cc_precompiler": {:hex, :cc_precompiler, "0.1.10", "47c9c08d8869cf09b41da36538f62bc1abd3e19e41701c2cea2675b53c704258", [:mix], [{:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "f6e046254e53cd6b41c6bacd70ae728011aa82b2742a80d6e2214855c6e06b22"},
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
"cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
"cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
"db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"},
"decimal": {:hex, :decimal, "2.2.0", "df3d06bb9517e302b1bd265c1e7f16cda51547ad9d99892049340841f3e15836", [:mix], [], "hexpm", "af8daf87384b51b7e611fb1a1f2c4d4876b65ef968fa8bd3adf44cff401c7f21"},
"ecto": {:hex, :ecto, "3.12.4", "267c94d9f2969e6acc4dd5e3e3af5b05cdae89a4d549925f3008b2b7eb0b93c3", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ef04e4101688a67d061e1b10d7bc1fbf00d1d13c17eef08b71d070ff9188f747"},
"ecto_sql": {:hex, :ecto_sql, "3.12.1", "c0d0d60e85d9ff4631f12bafa454bc392ce8b9ec83531a412c12a0d415a3a4d0", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "aff5b958a899762c5f09028c847569f7dfb9cc9d63bdb8133bff8a5546de6bf5"},
"ecto_sqlite3": {:hex, :ecto_sqlite3, "0.17.4", "48dd9c6d0fc10875a64545d04f0478b142898b6f0e73ae969becf5726f834d22", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.12", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:exqlite, "~> 0.22", [hex: :exqlite, repo: "hexpm", optional: false]}], "hexpm", "f67372e0eae5e5cbdd1d145e78e670fc5064d5810adf99d104d364cb920e306a"},
"elixir_make": {:hex, :elixir_make, "0.9.0", "6484b3cd8c0cee58f09f05ecaf1a140a8c97670671a6a0e7ab4dc326c3109726", [:mix], [], "hexpm", "db23d4fd8b757462ad02f8aa73431a426fe6671c80b200d9710caf3d1dd0ffdb"},
"exqlite": {:hex, :exqlite, "0.27.0", "2ef6021862e74c6253d1fb1f5701bd47e4e779b035d34daf2a13ec83945a05ba", [:make, :mix], [{:cc_precompiler, "~> 0.1", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.8", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "b947b9db15bb7aad11da6cd18a0d8b78f7fcce89508a27a5b9be18350fe12c59"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.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.4.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", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
"hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"},
"httpoison": {:hex, :httpoison, "2.2.1", "87b7ed6d95db0389f7df02779644171d7319d319178f6680438167d7b69b1f3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "51364e6d2f429d80e14fe4b5f8e39719cacd03eb3f9a9286e61e216feac2d2df"},
"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.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
"jose": {:hex, :jose, "1.11.10", "a903f5227417bd2a08c8a00a0cbcc458118be84480955e8d251297a425723f83", [:mix, :rebar3], [], "hexpm", "0d6cd36ff8ba174db29148fc112b5842186b68a90ce9fc2b3ec3afe76593e614"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"},
"mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"},
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
"plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"},
"plug_cowboy": {:hex, :plug_cowboy, "2.7.2", "fdadb973799ae691bf9ecad99125b16625b1c6039999da5fe544d99218e662e4", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "245d8a11ee2306094840c000e8816f0cbed69a23fc0ac2bcf8d7835ae019bb2f"},
"plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"},
"plug_live_reload": {:hex, :plug_live_reload, "0.1.1", "5ddf1a08b0dcc9f3623e87492d8a517cb107f9aacb1f3524267cd142e90184b5", [:mix], [{:cowboy, "~> 2.9", [hex: :cowboy, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.1", [hex: :file_system, repo: "hexpm", optional: false]}, {:plug, "~> 1.12", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ac91b75077b9a454ef035c6a9f58cc1708a27c6a97532aa910f11224e1df1615"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
"thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
"web_push_elixir": {:hex, :web_push_elixir, "0.4.0", "e4671facae5d2cadbf0c9fcebe99bac7ac5a6aad32fc47e6d3e08d82f65dfaf4", [:mix], [{:httpoison, "~> 2.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:jose, "~> 1.11", [hex: :jose, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: false]}], "hexpm", "98ac602ce15916758fb11e9a81c9c26c90b001820aced03d53fe182750401f4c"},
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
}

View file

@ -0,0 +1,58 @@
defmodule Jenot.Repo.Migrations.InitialSchema do
use Ecto.Migration
def change do
create table(:accounts, primary_key: false) do
add :id, :uuid, primary_key: true
timestamps(type: :datetime_usec)
end
create table(:notes, primary_key: false) do
add :id, :uuid, null: false, primary_key: true
add :internal_id, :text, null: false
add :account_id, references(:accounts, on_delete: :delete_all), null: false
add :title, :text, null: false, default: ""
add :content, :text, null: false, default: ""
timestamps(type: :datetime_usec)
end
create index(:notes, [:account_id])
create unique_index(:notes, [:account_id, :internal_id])
create table(:subscriptions, primary_key: false) do
add :id, :uuid, null: false, primary_key: true
add :endpoint, :text, null: false
add :token, :text, null: false
add :auth, :text, null: false
add :hash, :text, null: false
add :account_id, references(:accounts, on_delete: :delete_all), null: false
timestamps(type: :datetime_usec)
end
create index(:subscriptions, [:account_id])
create unique_index(:subscriptions, [:hash])
create table(:reminders, primary_key: false) do
add :id, :uuid, primary_key: true
add :date, :date, null: false
add :time, :time
add :day_of_week, :integer
add :repeat_period, :text
add :repeat_count, :integer
add :note_id, references(:note, on_delete: :delete_all), null: false
timestamps(type: :datetime_usec)
end
create index(:reminders, [:note_id])
end
end

View file

@ -1,6 +1,11 @@
const putInCache = async (request, response) => {
const requestUrl = URL.parse(request.url);
// We don't cache API requests
if (!requestUrl.pathname.startsWith('/api/')) {
const cache = await caches.open("v1");
await cache.put(request, response);
}
};
const cacheFirst = async ({ request, fallbackUrl }) => {