Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Edit poll issues and auth logic to be set #14

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25,663 changes: 0 additions & 25,663 deletions .elixir-tools/next-ls.log

This file was deleted.

4 changes: 4 additions & 0 deletions config/dev.exs
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,7 @@ config :phoenix, :plug_init_mode, :runtime

# Disable swoosh api client as it is only required for production adapters.
config :swoosh, :api_client, false

config :polly, PollyWeb.Endpoint,
http: [port: 4000],
server: true
25 changes: 24 additions & 1 deletion lib/polly/polls.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule Polly.Polls do
@moduledoc """
This module holds functions related to CRUD operations for Polls
"""
alias Polly.Schema.Poll
alias Polly.Schema.{Poll}

@spec list_polls() :: [Poll.t()]
def list_polls() do
Expand All @@ -19,6 +19,15 @@ defmodule Polly.Polls do
end
end

def has_option?(poll_id, option_id) do
poll_id
|> Polly.PollsManager.get_poll!(false)
|> Map.fetch!(:options)
|> Enum.any?(fn option ->
option.id == option_id
end)
end

@spec get_poll!(binary()) :: Poll.t()
def get_poll!(id) do
Polly.PollsManager.get_poll_simple!(id)
Expand All @@ -31,6 +40,20 @@ defmodule Polly.Polls do
|> do_create_poll()
end

def create_poll(params) do
Poll.changeset(%Poll{},params)
|> Ecto.Changeset.apply_action(:insert)
|> case do
{:ok, poll} ->
:ets.insert(:polls, {poll.id, poll})
{:ok, poll}

{:error, changeset} ->
{:error, changeset}
end
end


defp do_create_poll({:ok, %Poll{} = poll}) do
:ok = Polly.PollsManager.add_poll(poll)
{:ok, poll}
Expand Down
1 change: 0 additions & 1 deletion lib/polly/polls_manager.ex
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ defmodule Polly.PollsManager do
Poll.changeset(poll, attrs)
end


@spec update_poll(Poll.t()) :: :ok | {:error, any()}
def update_poll(%Poll{} = _poll) do
# Your ETS or other storage logic to update the poll
Expand Down
11 changes: 5 additions & 6 deletions lib/polly/schema/poll.ex
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,9 @@ defmodule Polly.Schema.Poll do
changeset
end

# def changeset(poll, attrs) do
# poll
# |> cast(attrs, [:title, :description])
# |> validate_required([:title, :description])
# end
# defstruct title: nil, options: [], total_votes: 0, created_at: nil
@spec has_option?(t(), binary()) :: boolean()
def has_option?(%Poll{options: options}, option_id) do
Enum.any?(options, fn option -> option.id == option_id end)
end

end
1 change: 0 additions & 1 deletion lib/polly/storage/behaviour.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,4 @@ defmodule Polly.StorageBehaviour do
@callback safe_lookup_element(binary()) :: integer()
@callback update_poll(binary(), Poll.t()) :: :ok | {:error, atom()}
# @callback replace_option_votes(Poll.t(), boolean()) :: Poll.t()

end
46 changes: 40 additions & 6 deletions lib/polly/storage/ets_storage.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,21 @@ defmodule Polly.ETSStorage do
@impl Polly.StorageBehaviour
def init() do
:ets.new(@polls, [:public, :named_table, write_concurrency: true, read_concurrency: true])
:ets.new(@polls_votes, [:public, :named_table, write_concurrency: true, read_concurrency: true])
:ets.new(@polls_options_votes, [:public, :named_table, write_concurrency: true, read_concurrency: true])

:ets.new(@polls_votes, [
:public,
:named_table,
write_concurrency: true,
read_concurrency: true
])

:ets.new(@polls_options_votes, [
:public,
:named_table,
write_concurrency: true,
read_concurrency: true
])

:ok
end

Expand Down Expand Up @@ -46,21 +59,31 @@ defmodule Polly.ETSStorage do

@impl Polly.StorageBehaviour
def get_poll!(poll_id, with_option_votes \\ false) do
:ets.lookup_element(@polls, poll_id, 2)
|> Map.replace(:total_votes, get_poll_votes!(poll_id))
|> replace_option_votes(with_option_votes)
case :ets.lookup(@polls, poll_id) do
[{^poll_id, poll}] ->
poll
|> Map.replace(:total_votes, get_poll_votes!(poll_id))
|> replace_option_votes(with_option_votes)

[] ->
raise ArgumentError, message: "Poll with ID #{poll_id} not found"
end
end

@impl Polly.StorageBehaviour
def get_poll_votes!(poll_id) do
:ets.lookup_element(@polls_votes, poll_id, 2)
case :ets.lookup(@polls_votes, poll_id) do
[{^poll_id, votes}] -> votes
[] -> 0
end
end

def replace_option_votes(poll, true) do
updated_options =
Enum.map(poll.options, fn option ->
Map.replace(option, :votes, safe_lookup_element(option.id))
end)

Map.replace(poll, :options, updated_options)
end

Expand Down Expand Up @@ -93,4 +116,15 @@ defmodule Polly.ETSStorage do
{:error, :poll_not_found}
end
end

def poll_exists?(poll_id) do
case :ets.lookup(@polls, poll_id) do
[{^poll_id, _poll}] -> true
_ -> false
end
end

def list_all_polls do
:ets.tab2list(@polls)
end
end
31 changes: 21 additions & 10 deletions lib/polly_web/components/core_components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ defmodule PollyWeb.CoreComponents do
<.icon name="hero-x-mark-solid" class="h-5 w-5" />
</button>
</div>

<div id={"#{@id}-content"}>
<%= render_slot(@inner_block) %>
</div>
Expand Down Expand Up @@ -121,10 +122,11 @@ defmodule PollyWeb.CoreComponents do
>
<p :if={@title} class="flex items-center gap-1.5 text-sm font-semibold leading-6">
<.icon :if={@kind == :info} name="hero-information-circle-mini" class="h-4 w-4" />
<.icon :if={@kind == :error} name="hero-exclamation-circle-mini" class="h-4 w-4" />
<%= @title %>
<.icon :if={@kind == :error} name="hero-exclamation-circle-mini" class="h-4 w-4" /> <%= @title %>
</p>

<p class="mt-2 text-sm leading-5"><%= msg %></p>

<button type="button" class="group absolute top-1 right-1 p-2" aria-label={gettext("close")}>
<.icon name="hero-x-mark-solid" class="h-5 w-5 opacity-40 group-hover:opacity-70" />
</button>
Expand Down Expand Up @@ -286,9 +288,9 @@ defmodule PollyWeb.CoreComponents do
checked={@checked}
class="rounded border-zinc-300 text-zinc-900 focus:ring-0"
{@rest}
/>
<%= @label %>
/> <%= @label %>
</label>

<.error :for={msg <- @errors}><%= msg %></.error>
</div>
"""
Expand All @@ -298,6 +300,7 @@ defmodule PollyWeb.CoreComponents do
~H"""
<div phx-feedback-for={@name}>
<.label for={@id}><%= @label %></.label>

<select
id={@id}
name={@name}
Expand All @@ -306,8 +309,9 @@ defmodule PollyWeb.CoreComponents do
{@rest}
>
<option :if={@prompt} value=""><%= @prompt %></option>
<%= Phoenix.HTML.Form.options_for_select(@options, @value) %>
<%= Phoenix.HTML.Form.options_for_select(@options, @value) %>
</select>

<.error :for={msg <- @errors}><%= msg %></.error>
</div>
"""
Expand All @@ -317,7 +321,7 @@ defmodule PollyWeb.CoreComponents do
~H"""
<div phx-feedback-for={@name}>
<.label for={@id}><%= @label %></.label>
<textarea
<textarea
id={@id}
name={@name}
class={[
Expand All @@ -338,6 +342,7 @@ defmodule PollyWeb.CoreComponents do
~H"""
<div phx-feedback-for={@name}>
<.label for={@id}><%= @label %></.label>

<input
type={@type}
name={@name}
Expand Down Expand Up @@ -378,8 +383,9 @@ defmodule PollyWeb.CoreComponents do
def error(assigns) do
~H"""
<p class="mt-3 flex gap-3 text-sm leading-6 text-rose-600 phx-no-feedback:hidden">
<.icon name="hero-exclamation-circle-mini" class="mt-0.5 h-5 w-5 flex-none" />
<%= render_slot(@inner_block) %>
<.icon name="hero-exclamation-circle-mini" class="mt-0.5 h-5 w-5 flex-none" /> <%= render_slot(
@inner_block
) %>
</p>
"""
end
Expand All @@ -400,10 +406,12 @@ defmodule PollyWeb.CoreComponents do
<h1 class="text-xl font-semibold leading-8 text-zinc-800">
<%= render_slot(@inner_block) %>
</h1>

<p :if={@subtitle != []} class="mt-2 text-md leading-6 text-zinc-600">
<%= render_slot(@subtitle) %>
</p>
</div>

<div class="flex-none"><%= render_slot(@actions) %></div>
</header>
"""
Expand Down Expand Up @@ -446,9 +454,11 @@ defmodule PollyWeb.CoreComponents do
<thead class="text-sm text-left leading-6 text-zinc-500">
<tr>
<th :for={col <- @col} class="p-0 pr-6 pb-4 font-normal"><%= col[:label] %></th>

<th class="relative p-0 pb-4"><span class="sr-only"><%= gettext("Actions") %></span></th>
</tr>
</thead>

<tbody
id={@id}
phx-update={match?(%Phoenix.LiveView.LiveStream{}, @rows) && "stream"}
Expand All @@ -467,6 +477,7 @@ defmodule PollyWeb.CoreComponents do
</span>
</div>
</td>

<td :if={@action != []} class="relative w-14 p-0">
<div class="relative whitespace-nowrap py-4 text-right text-sm font-medium">
<span class="absolute -inset-y-px -right-4 left-0 group-hover:bg-zinc-50 sm:rounded-r-xl" />
Expand Down Expand Up @@ -505,6 +516,7 @@ defmodule PollyWeb.CoreComponents do
<dl class="-my-4 divide-y divide-zinc-100">
<div :for={item <- @item} class="flex gap-4 py-4 text-sm leading-6 sm:gap-8">
<dt class="w-1/4 flex-none text-zinc-500"><%= item.title %></dt>

<dd class="text-zinc-700"><%= render_slot(item) %></dd>
</div>
</dl>
Expand All @@ -529,8 +541,7 @@ defmodule PollyWeb.CoreComponents do
navigate={@navigate}
class="text-sm font-semibold leading-6 text-zinc-900 hover:text-zinc-700"
>
<.icon name="hero-arrow-left-solid" class="h-3 w-3" />
<%= render_slot(@inner_block) %>
<.icon name="hero-arrow-left-solid" class="h-3 w-3" /> <%= render_slot(@inner_block) %>
</.link>
</div>
"""
Expand Down
Loading
Loading