summaryrefslogtreecommitdiff
path: root/lib/aggiedit/rooms.ex
blob: 82461944b7faca3ef196923eb16199e4581d3b95 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
defmodule Aggiedit.Rooms do
  @moduledoc """
  The Rooms context.
  """

  import Ecto.Query, warn: false
  alias Aggiedit.Repo

  alias Aggiedit.Accounts.User
  alias Aggiedit.Rooms.Room

  alias Aggiedit.Post.{Vote, Comment}

  alias Phoenix.PubSub

  def list_rooms do
    Repo.all(Room)
  end

  def get_room!(id), do: Repo.get!(Room, id)

  def create_room(attrs \\ %{}) do
    %Room{}
    |> Room.changeset(attrs)
    |> Repo.insert()
  end

  def update_room(%Room{} = room, attrs) do
    room
    |> Room.changeset(attrs)
    |> Repo.update()
  end

  def delete_room(%Room{} = room) do
    Repo.delete(room)
  end

  def change_room(%Room{} = room, attrs \\ %{}) do
    Room.changeset(room, attrs)
  end

  def create_or_find_room_with_domain(domain) do
    case Repo.get_by(Room, domain: domain) do
      room=%Room{} -> {:ok, room}
      nil -> create_room(%{domain: domain})
    end
  end

  alias Aggiedit.Rooms.Post

  def list_posts do
    Repo.all(Post)
  end

  def posts_in_room(room_id) do
    Repo.all((from p in Post, where: p.room_id == ^room_id, order_by: [asc: :id], select: p))
  end

  def get_post!(id), do: Repo.get!(Post, id)

  def create_post(attrs, user, after_save \\ &{:ok, &1}) do
    user = Repo.preload(user, :room)

    %Post{}
    |> Repo.preload([:user, :room])
    |> Post.changeset(attrs)
    |> Ecto.Changeset.put_assoc(:user, user)
    |> Ecto.Changeset.put_assoc(:room, user.room)
    |> Repo.insert()
    |> broadcast_post_over_room(:post_created)
    |> post_saved(after_save)
  end

  def update_post(%Post{} = post, attrs, after_save \\ &{:ok, &1}) do
    post
    |> Post.changeset(attrs)
    |> Repo.update()
    |> broadcast_post_over_room(:post_updated)
    |> post_saved(after_save)
  end

  defp post_saved({:ok, post}, func) do
    {:ok, _post} = func.(post)
  end
  defp post_saved(error, _fun), do: error

  def delete_post(%Post{} = post) do
    Repo.delete(post)
    |> broadcast_post_over_room(:post_deleted)
  end

  def change_post(%Post{} = post, attrs \\ %{}) do
    Post.changeset(post, attrs)
  end

  def vote_count(post) do
    post
    |> Repo.preload(:votes)
    |> Map.get(:votes)
    |> Enum.map(fn vote -> if vote.is_up, do: 1, else: -1 end)
    |> Enum.sum()
  end

  def vote_post(%Post{} = post, %User{} = user, direction) do
    is_up = direction == "upvote"
    %Vote{is_up: is_up, user: user, post: post}
    |> Repo.insert(on_conflict: [set: [is_up: is_up]], conflict_target: [:user_id, :post_id])
    
    post = change_post(post, %{score: vote_count(post)})
    |> Repo.update()

    broadcast_post_over_room(post, :post_voted)
  end

  def comment_post(%Post{} = post, %User{} = user, comment) do
    Repo.insert(%Comment{comment: comment, user: user, post: post})
  end

  defp broadcast_post_over_room({:error, _reason}=error, _event), do: error
  defp broadcast_post_over_room({:ok, post}, event) do 
    PubSub.broadcast(Aggiedit.PubSub, "room:#{post.room_id}:posts", {event, post})
    {:ok, post}
  end

  def subscribe(room) do
    PubSub.subscribe(Aggiedit.PubSub, "room:#{room.id}:posts")
  end
end