Search
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
394549933d
commit
91a3805a47
@ -34,7 +34,7 @@
|
|||||||
<v-layout row>
|
<v-layout row>
|
||||||
<v-flex xs7>
|
<v-flex xs7>
|
||||||
<div class="headline">{{ actor.display_name }}</div>
|
<div class="headline">{{ actor.display_name }}</div>
|
||||||
<div><span class="subheading">@{{ actor.username }}</span><span v-if="actor.server">@{{ actor.server.address }}</span></div>
|
<div><span class="subheading">@{{ actor.username }}<span v-if="actor.domain">@{{ actor.domain }}</span></span></div>
|
||||||
<v-card-text v-if="actor.description" v-html="actor.description"></v-card-text>
|
<v-card-text v-if="actor.description" v-html="actor.description"></v-card-text>
|
||||||
</v-flex>
|
</v-flex>
|
||||||
</v-layout>
|
</v-layout>
|
||||||
@ -179,7 +179,7 @@ export default {
|
|||||||
required: true,
|
required: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
created() {
|
||||||
this.fetchData();
|
this.fetchData();
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -24,7 +24,22 @@
|
|||||||
:items="searchElement.items"
|
:items="searchElement.items"
|
||||||
:search-input.sync="search"
|
:search-input.sync="search"
|
||||||
v-model="searchSelect"
|
v-model="searchSelect"
|
||||||
></v-select>
|
>
|
||||||
|
<template slot="item" slot-scope="data">
|
||||||
|
<template v-if="typeof data.item !== 'object'">
|
||||||
|
<v-list-tile-content v-text="data.item"></v-list-tile-content>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<v-list-tile-avatar>
|
||||||
|
<img :src="data.item.avatar">
|
||||||
|
</v-list-tile-avatar>
|
||||||
|
<v-list-tile-content>
|
||||||
|
<v-list-tile-title v-html="username_with_domain(data.item)"></v-list-tile-title>
|
||||||
|
<v-list-tile-sub-title v-html="data.item.type"></v-list-tile-sub-title>
|
||||||
|
</v-list-tile-content>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</v-select>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer></v-spacer>
|
||||||
<v-menu
|
<v-menu
|
||||||
offset-y
|
offset-y
|
||||||
@ -58,7 +73,7 @@
|
|||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-menu>
|
</v-menu>
|
||||||
<v-btn flat @click="$router.push({name: 'Account', params: {'id': getUser().actor.id}})" v-if="$store.state.user">{{ this.displayed_name }}</v-btn>
|
<v-btn flat @click="$router.push({name: 'Account', params: { name: getUser().actor.username }})" v-if="$store.state.user">{{ this.displayed_name }}</v-btn>
|
||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -88,10 +103,12 @@
|
|||||||
},
|
},
|
||||||
searchSelect(val) {
|
searchSelect(val) {
|
||||||
console.log(val);
|
console.log(val);
|
||||||
if (val.hasOwnProperty('addressLocality')) {
|
if (val.type === 'Event') {
|
||||||
|
this.$router.push({name: 'Event', params: { name: val.organizer.username, slug: val.slug }});
|
||||||
|
} else if (val.type === 'Locality') {
|
||||||
this.$router.push({name: 'EventList', params: {location: val.geohash}});
|
this.$router.push({name: 'EventList', params: {location: val.geohash}});
|
||||||
} else {
|
} else {
|
||||||
this.$router.push({name: 'Account', params: {id: val.id}});
|
this.$router.push({name: 'Account', params: { name : this.username_with_domain(val) }});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -101,35 +118,47 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
username_with_domain(actor) {
|
||||||
|
if (actor.type !== 'Event') {
|
||||||
|
return actor.username + (actor.domain === null ? '' : `@${actor.domain}`)
|
||||||
|
}
|
||||||
|
return actor.title;
|
||||||
|
},
|
||||||
getUser() {
|
getUser() {
|
||||||
return this.$store.state.user === undefined ? false : this.$store.state.user;
|
return this.$store.state.user === undefined ? false : this.$store.state.user;
|
||||||
},
|
},
|
||||||
querySelections(searchTerm) {
|
querySelections(searchTerm) {
|
||||||
this.searchElement.loading = true;
|
this.searchElement.loading = true;
|
||||||
eventFetch('/find/', this.$store, {method: 'POST', body: JSON.stringify({search: searchTerm})})
|
eventFetch(`/search/${searchTerm}`, this.$store)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then((results) => {
|
.then((results) => {
|
||||||
|
console.log('results');
|
||||||
console.log(results);
|
console.log(results);
|
||||||
const accountResults = results.accounts.map((result) => {
|
const accountResults = results.data.actors.map((result) => {
|
||||||
if (result.server) {
|
if (result.domain) {
|
||||||
result.displayedText = `${result.username}@${result.server.address}`;
|
result.displayedText = `${result.username}@${result.domain}`;
|
||||||
} else {
|
} else {
|
||||||
result.displayedText = result.username;
|
result.displayedText = result.username;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
const cities = new Set();
|
|
||||||
const placeResults = results.places.map((result) => {
|
const eventsResults = results.data.events.map((result) => {
|
||||||
result.displayedText = result.addressLocality;
|
result.displayedText = result.title;
|
||||||
return result;
|
return result;
|
||||||
}).filter((result) => {
|
|
||||||
if (cities.has(result.addressLocality)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
cities.add(result.addressLocality);
|
|
||||||
return true;
|
|
||||||
});
|
});
|
||||||
this.searchElement.items = accountResults.concat(placeResults);
|
// const cities = new Set();
|
||||||
|
// const placeResults = results.places.map((result) => {
|
||||||
|
// result.displayedText = result.addressLocality;
|
||||||
|
// return result;
|
||||||
|
// }).filter((result) => {
|
||||||
|
// if (cities.has(result.addressLocality)) {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// cities.add(result.addressLocality);
|
||||||
|
// return true;
|
||||||
|
// });
|
||||||
|
this.searchElement.items = accountResults.concat(eventsResults);
|
||||||
this.searchElement.loading = false;
|
this.searchElement.loading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -77,14 +77,14 @@ defmodule Eventos.Actors.Actor do
|
|||||||
actor
|
actor
|
||||||
|> Ecto.Changeset.cast(attrs, [:url, :outbox_url, :inbox_url, :following_url, :followers_url, :type, :name, :domain, :summary, :preferred_username, :public_key, :private_key, :manually_approves_followers, :suspended])
|
|> Ecto.Changeset.cast(attrs, [:url, :outbox_url, :inbox_url, :following_url, :followers_url, :type, :name, :domain, :summary, :preferred_username, :public_key, :private_key, :manually_approves_followers, :suspended])
|
||||||
|> validate_required([:preferred_username, :public_key, :suspended, :url])
|
|> validate_required([:preferred_username, :public_key, :suspended, :url])
|
||||||
|> unique_constraint(:name, name: :actors_username_domain_index)
|
|> unique_constraint(:prefered_username, name: :actors_preferred_username_domain_index)
|
||||||
end
|
end
|
||||||
|
|
||||||
def registration_changeset(%Actor{} = actor, attrs) do
|
def registration_changeset(%Actor{} = actor, attrs) do
|
||||||
actor
|
actor
|
||||||
|> Ecto.Changeset.cast(attrs, [:name, :domain, :display_name, :description, :private_key, :public_key, :suspended, :url])
|
|> Ecto.Changeset.cast(attrs, [:preferred_username, :domain, :name, :summary, :private_key, :public_key, :suspended, :url, :type])
|
||||||
|> validate_required([:preferred_username, :public_key, :suspended, :url])
|
|> validate_required([:preferred_username, :public_key, :suspended, :url, :type])
|
||||||
|> unique_constraint(:name)
|
|> unique_constraint(:prefered_username, name: :actors_preferred_username_domain_index)
|
||||||
end
|
end
|
||||||
|
|
||||||
@email_regex ~r/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
|
@email_regex ~r/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
|
||||||
|
@ -196,7 +196,12 @@ defmodule Eventos.Actors do
|
|||||||
end
|
end
|
||||||
|
|
||||||
def get_actor_by_name(name) do
|
def get_actor_by_name(name) do
|
||||||
Repo.get_by!(Actor, preferred_username: name)
|
actor = case String.split(name, "@") do
|
||||||
|
[name] ->
|
||||||
|
Repo.get_by(Actor, preferred_username: name)
|
||||||
|
[name, domain] ->
|
||||||
|
Repo.get_by(Actor, preferred_username: name, domain: domain)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_local_actor_by_name(name) do
|
def get_local_actor_by_name(name) do
|
||||||
@ -231,6 +236,44 @@ defmodule Eventos.Actors do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Find local users by it's username
|
||||||
|
"""
|
||||||
|
def find_local_by_username(username) do
|
||||||
|
actors = Repo.all from a in Actor, where: (ilike(a.preferred_username, ^like_sanitize(username)) or ilike(a.name, ^like_sanitize(username))) and is_nil(a.domain)
|
||||||
|
Repo.preload(actors, :organized_events)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Find actors by their name or displayed name
|
||||||
|
"""
|
||||||
|
def find_actors_by_username(username) do
|
||||||
|
Repo.all from a in Actor, where: ilike(a.preferred_username, ^like_sanitize(username)) or ilike(a.name, ^like_sanitize(username))
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Sanitize the LIKE queries
|
||||||
|
"""
|
||||||
|
defp like_sanitize(value) do
|
||||||
|
"%" <> String.replace(value, ~r/([\\%_])/, "\\1") <> "%"
|
||||||
|
end
|
||||||
|
|
||||||
|
@email_regex ~r/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
|
||||||
|
def search(name) do
|
||||||
|
case find_actors_by_username(name) do # find already saved accounts
|
||||||
|
[] ->
|
||||||
|
with true <- Regex.match?(@email_regex, name), # no accounts found, let's test if it's an username@domain.tld
|
||||||
|
{:ok, actor} <- ActivityPub.find_or_make_actor_from_nickname(name) do # creating the actor in that case
|
||||||
|
{:ok, [actor]}
|
||||||
|
else
|
||||||
|
false -> {:ok, []}
|
||||||
|
{:error, err} -> {:error, err} # error fingering the actor
|
||||||
|
end
|
||||||
|
actors = [_|_] ->
|
||||||
|
{:ok, actors} # actors already saved found !
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Get an user by email
|
Get an user by email
|
||||||
"""
|
"""
|
||||||
@ -288,6 +331,32 @@ defmodule Eventos.Actors do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def register_bot_account(%{name: name, summary: summary}) do
|
||||||
|
key = :public_key.generate_key({:rsa, 2048, 65537})
|
||||||
|
entry = :public_key.pem_entry_encode(:RSAPrivateKey, key)
|
||||||
|
pem = :public_key.pem_encode([entry]) |> String.trim_trailing()
|
||||||
|
|
||||||
|
{:ok, rsa_priv_key} = ExPublicKey.generate_key()
|
||||||
|
{:ok, rsa_pub_key} = ExPublicKey.public_key_from_private_key(rsa_priv_key)
|
||||||
|
|
||||||
|
actor = Eventos.Actors.Actor.registration_changeset(%Eventos.Actors.Actor{}, %{
|
||||||
|
preferred_username: name,
|
||||||
|
domain: nil,
|
||||||
|
private_key: pem,
|
||||||
|
public_key: "toto",
|
||||||
|
url: EventosWeb.Endpoint.url() <> "/@" <> name,
|
||||||
|
summary: summary,
|
||||||
|
type: :Service
|
||||||
|
})
|
||||||
|
|
||||||
|
try do
|
||||||
|
Eventos.Repo.insert!(actor)
|
||||||
|
rescue
|
||||||
|
e in Ecto.InvalidChangesetError ->
|
||||||
|
{:error, e}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Creates a user.
|
Creates a user.
|
||||||
@ -450,4 +519,105 @@ defmodule Eventos.Actors do
|
|||||||
Member.changeset(member, %{})
|
Member.changeset(member, %{})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
alias Eventos.Actors.Bot
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Returns the list of bots.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> list_bots()
|
||||||
|
[%Bot{}, ...]
|
||||||
|
|
||||||
|
"""
|
||||||
|
def list_bots do
|
||||||
|
Repo.all(Bot)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Gets a single bot.
|
||||||
|
|
||||||
|
Raises `Ecto.NoResultsError` if the Bot does not exist.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> get_bot!(123)
|
||||||
|
%Bot{}
|
||||||
|
|
||||||
|
iex> get_bot!(456)
|
||||||
|
** (Ecto.NoResultsError)
|
||||||
|
|
||||||
|
"""
|
||||||
|
def get_bot!(id), do: Repo.get!(Bot, id)
|
||||||
|
|
||||||
|
@spec get_bot_by_actor(Actor.t) :: Bot.t
|
||||||
|
def get_bot_by_actor(%Actor{} = actor) do
|
||||||
|
Repo.get_by!(Bot, actor_id: actor.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Creates a bot.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> create_bot(%{field: value})
|
||||||
|
{:ok, %Bot{}}
|
||||||
|
|
||||||
|
iex> create_bot(%{field: bad_value})
|
||||||
|
{:error, %Ecto.Changeset{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def create_bot(attrs \\ %{}) do
|
||||||
|
%Bot{}
|
||||||
|
|> Bot.changeset(attrs)
|
||||||
|
|> Repo.insert()
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Updates a bot.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> update_bot(bot, %{field: new_value})
|
||||||
|
{:ok, %Bot{}}
|
||||||
|
|
||||||
|
iex> update_bot(bot, %{field: bad_value})
|
||||||
|
{:error, %Ecto.Changeset{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def update_bot(%Bot{} = bot, attrs) do
|
||||||
|
bot
|
||||||
|
|> Bot.changeset(attrs)
|
||||||
|
|> Repo.update()
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Deletes a Bot.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> delete_bot(bot)
|
||||||
|
{:ok, %Bot{}}
|
||||||
|
|
||||||
|
iex> delete_bot(bot)
|
||||||
|
{:error, %Ecto.Changeset{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def delete_bot(%Bot{} = bot) do
|
||||||
|
Repo.delete(bot)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Returns an `%Ecto.Changeset{}` for tracking bot changes.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> change_bot(bot)
|
||||||
|
%Ecto.Changeset{source: %Bot{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def change_bot(%Bot{} = bot) do
|
||||||
|
Bot.changeset(bot, %{})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
25
lib/eventos/actors/bot.ex
Normal file
25
lib/eventos/actors/bot.ex
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
defmodule Eventos.Actors.Bot do
|
||||||
|
@moduledoc """
|
||||||
|
Represents a local bot
|
||||||
|
"""
|
||||||
|
use Ecto.Schema
|
||||||
|
import Ecto.Changeset
|
||||||
|
alias Eventos.Actors.{Actor, User, Bot}
|
||||||
|
|
||||||
|
|
||||||
|
schema "bots" do
|
||||||
|
field :source, :string
|
||||||
|
field :type, :string, default: :ics
|
||||||
|
belongs_to :actor, Actor
|
||||||
|
belongs_to :user, User
|
||||||
|
|
||||||
|
timestamps()
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
def changeset(bot, attrs) do
|
||||||
|
bot
|
||||||
|
|> cast(attrs, [:source, :type, :actor_id, :user_id])
|
||||||
|
|> validate_required([:source])
|
||||||
|
end
|
||||||
|
end
|
@ -34,7 +34,7 @@ defmodule Eventos.Events do
|
|||||||
offset: ^start,
|
offset: ^start,
|
||||||
preload: [:organizer_actor, :category, :sessions, :tracks, :tags, :participants, :address]
|
preload: [:organizer_actor, :category, :sessions, :tracks, :tags, :participants, :address]
|
||||||
events = Repo.all(query)
|
events = Repo.all(query)
|
||||||
count_events = Repo.one(from e in Event, select: count(e.id))
|
count_events = Repo.one(from e in Event, select: count(e.id), where: e.organizer_actor_id == ^actor_id)
|
||||||
{:ok, events, count_events}
|
{:ok, events, count_events}
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -109,6 +109,21 @@ defmodule Eventos.Events do
|
|||||||
Repo.preload(event, [:organizer_actor, :category, :sessions, :tracks, :tags, :participants, :address])
|
Repo.preload(event, [:organizer_actor, :category, :sessions, :tracks, :tags, :participants, :address])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Find events by name
|
||||||
|
"""
|
||||||
|
def find_events_by_name(name) do
|
||||||
|
events = Repo.all from a in Event, where: ilike(a.title, ^like_sanitize(name))
|
||||||
|
Repo.preload(events, [:organizer_actor])
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Sanitize the LIKE queries
|
||||||
|
"""
|
||||||
|
defp like_sanitize(value) do
|
||||||
|
"%" <> String.replace(value, ~r/([\\%_])/, "\\1") <> "%"
|
||||||
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Creates a event.
|
Creates a event.
|
||||||
|
|
||||||
@ -205,6 +220,11 @@ defmodule Eventos.Events do
|
|||||||
"""
|
"""
|
||||||
def get_category!(id), do: Repo.get!(Category, id)
|
def get_category!(id), do: Repo.get!(Category, id)
|
||||||
|
|
||||||
|
@spec get_category_by_title(String.t) :: tuple()
|
||||||
|
def get_category_by_title(title) when is_binary(title) do
|
||||||
|
Repo.get_by(Category, title: title)
|
||||||
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Creates a category.
|
Creates a category.
|
||||||
|
|
||||||
|
@ -20,10 +20,11 @@ defmodule EventosWeb.ActorController do
|
|||||||
render(conn, "show.json", actor: actor)
|
render(conn, "show.json", actor: actor)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@email_regex ~r/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
|
||||||
def search(conn, %{"name" => name}) do
|
def search(conn, %{"name" => name}) do
|
||||||
with {:ok, actor} <- ActivityPub.make_actor_from_nickname(name) do
|
case Actors.search(name) do # find already saved accounts
|
||||||
render(conn, "acccount_basic.json", actor: actor)
|
{:ok, actors} ->
|
||||||
else
|
render(conn, "index.json", actors: actors)
|
||||||
{:error, err} -> json(conn, err)
|
{:error, err} -> json(conn, err)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
46
lib/eventos_web/controllers/bot_controller.ex
Normal file
46
lib/eventos_web/controllers/bot_controller.ex
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
defmodule EventosWeb.BotController do
|
||||||
|
use EventosWeb, :controller
|
||||||
|
|
||||||
|
alias Eventos.Actors
|
||||||
|
alias Eventos.Actors.Bot
|
||||||
|
|
||||||
|
action_fallback EventosWeb.FallbackController
|
||||||
|
|
||||||
|
def index(conn, _params) do
|
||||||
|
bots = Actors.list_bots()
|
||||||
|
render(conn, "index.json", bots: bots)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create(conn, %{"bot" => bot_params}) do
|
||||||
|
with user <- Guardian.Plug.current_resource,
|
||||||
|
bot_params <- Map.put(bot_params, "user_id", user.id),
|
||||||
|
{:ok, actor } <- Actors.register_bot_account(%{name: bot_params["name"], summary: bot_params["summary"]}),
|
||||||
|
bot_params <- Map.put(bot_params, "actor_id", actor.id),
|
||||||
|
{:ok, %Bot{} = bot} <- Actors.create_bot(bot_params) do
|
||||||
|
conn
|
||||||
|
|> put_status(:created)
|
||||||
|
|> put_resp_header("location", bot_path(conn, :show, bot))
|
||||||
|
|> render("show.json", bot: bot)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def show(conn, %{"id" => id}) do
|
||||||
|
bot = Actors.get_bot!(id)
|
||||||
|
render(conn, "show.json", bot: bot)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(conn, %{"id" => id, "bot" => bot_params}) do
|
||||||
|
bot = Actors.get_bot!(id)
|
||||||
|
|
||||||
|
with {:ok, %Bot{} = bot} <- Actors.update_bot(bot, bot_params) do
|
||||||
|
render(conn, "show.json", bot: bot)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete(conn, %{"id" => id}) do
|
||||||
|
bot = Actors.get_bot!(id)
|
||||||
|
with {:ok, %Bot{}} <- Actors.delete_bot(bot) do
|
||||||
|
send_resp(conn, :no_content, "")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -35,6 +35,11 @@ defmodule EventosWeb.EventController do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def search(conn, %{"name" => name}) do
|
||||||
|
events = Events.find_events_by_name(name)
|
||||||
|
render(conn, "index.json", events: events)
|
||||||
|
end
|
||||||
|
|
||||||
def show(conn, %{"username" => username, "slug" => slug}) do
|
def show(conn, %{"username" => username, "slug" => slug}) do
|
||||||
event = Events.get_event_full_by_name_and_slug!(username, slug)
|
event = Events.get_event_full_by_name_and_slug!(username, slug)
|
||||||
render(conn, "show.json", event: event)
|
render(conn, "show.json", event: event)
|
||||||
|
20
lib/eventos_web/controllers/search_controller.ex
Normal file
20
lib/eventos_web/controllers/search_controller.ex
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
defmodule EventosWeb.SearchController do
|
||||||
|
@moduledoc """
|
||||||
|
Controller for Search
|
||||||
|
"""
|
||||||
|
use EventosWeb, :controller
|
||||||
|
|
||||||
|
alias Eventos.Events
|
||||||
|
alias Eventos.Actors
|
||||||
|
|
||||||
|
action_fallback EventosWeb.FallbackController
|
||||||
|
|
||||||
|
def search(conn, %{"name" => name}) do
|
||||||
|
events = Events.find_events_by_name(name)
|
||||||
|
case Actors.search(name) do # find already saved accounts
|
||||||
|
{:ok, actors} ->
|
||||||
|
render(conn, "search.json", events: events, actors: actors)
|
||||||
|
{:error, err} -> json(conn, err)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -39,11 +39,13 @@ defmodule EventosWeb.Router do
|
|||||||
post "/login", UserSessionController, :sign_in
|
post "/login", UserSessionController, :sign_in
|
||||||
#resources "/groups", GroupController, only: [:index, :show]
|
#resources "/groups", GroupController, only: [:index, :show]
|
||||||
get "/events", EventController, :index
|
get "/events", EventController, :index
|
||||||
|
get "/events/search/:name", EventController, :search
|
||||||
get "/events/:username/:slug", EventController, :show
|
get "/events/:username/:slug", EventController, :show
|
||||||
get "/events/:username/:slug/ics", EventController, :export_to_ics
|
get "/events/:username/:slug/ics", EventController, :export_to_ics
|
||||||
get "/events/:username/:slug/tracks", TrackController, :show_tracks_for_event
|
get "/events/:username/:slug/tracks", TrackController, :show_tracks_for_event
|
||||||
get "/events/:username/:slug/sessions", SessionController, :show_sessions_for_event
|
get "/events/:username/:slug/sessions", SessionController, :show_sessions_for_event
|
||||||
resources "/comments", CommentController, only: [:show]
|
resources "/comments", CommentController, only: [:show]
|
||||||
|
get "/bots/:id", BotController, :view
|
||||||
|
|
||||||
get "/actors", ActorController, :index
|
get "/actors", ActorController, :index
|
||||||
get "/actors/search/:name", ActorController, :search
|
get "/actors/search/:name", ActorController, :search
|
||||||
@ -53,6 +55,8 @@ defmodule EventosWeb.Router do
|
|||||||
resources "/sessions", SessionController, only: [:index, :show]
|
resources "/sessions", SessionController, only: [:index, :show]
|
||||||
resources "/tracks", TrackController, only: [:index, :show]
|
resources "/tracks", TrackController, only: [:index, :show]
|
||||||
resources "/addresses", AddressController, only: [:index, :show]
|
resources "/addresses", AddressController, only: [:index, :show]
|
||||||
|
|
||||||
|
get "/search/:name", SearchController, :search
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -70,9 +74,10 @@ defmodule EventosWeb.Router do
|
|||||||
patch "/events/:username/:slug", EventController, :update
|
patch "/events/:username/:slug", EventController, :update
|
||||||
put "/events/:username/:slug", EventController, :update
|
put "/events/:username/:slug", EventController, :update
|
||||||
delete "/events/:username/:slug", EventController, :delete
|
delete "/events/:username/:slug", EventController, :delete
|
||||||
resources "/comments", CommentController, except: [:new, :edit]
|
resources "/comments", CommentController, except: [:new, :edit, :show]
|
||||||
#post "/events/:id/request", EventRequestController, :create_for_event
|
#post "/events/:id/request", EventRequestController, :create_for_event
|
||||||
resources "/participant", ParticipantController
|
resources "/participant", ParticipantController
|
||||||
|
resources "/bots", BotController, except: [:new, :edit, :show]
|
||||||
#resources "/requests", EventRequestController
|
#resources "/requests", EventRequestController
|
||||||
#resources "/groups", GroupController, except: [:index, :show]
|
#resources "/groups", GroupController, except: [:index, :show]
|
||||||
#post "/groups/:id/request", GroupRequestController, :create_for_group
|
#post "/groups/:id/request", GroupRequestController, :create_for_group
|
||||||
|
@ -9,6 +9,7 @@ defmodule EventosWeb.ActivityPub.ActorView do
|
|||||||
alias Eventos.Service.ActivityPub
|
alias Eventos.Service.ActivityPub
|
||||||
alias Eventos.Service.ActivityPub.Transmogrifier
|
alias Eventos.Service.ActivityPub.Transmogrifier
|
||||||
alias Eventos.Service.ActivityPub.Utils
|
alias Eventos.Service.ActivityPub.Utils
|
||||||
|
alias Eventos.Activity
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
def render("actor.json", %{actor: actor}) do
|
def render("actor.json", %{actor: actor}) do
|
||||||
@ -123,10 +124,10 @@ defmodule EventosWeb.ActivityPub.ActorView do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render("activity.json", %{activity: activity}) do
|
def render("activity.json", %{activity: %Activity{local: local} = activity}) do
|
||||||
%{
|
%{
|
||||||
"id" => activity.data.url <> "/activity",
|
"id" => activity.data.url <> "/activity",
|
||||||
"type" => "Create",
|
"type" => if local do "Create" else "Announce" end,
|
||||||
"actor" => activity.data.organizer_actor.url,
|
"actor" => activity.data.organizer_actor.url,
|
||||||
"published" => Timex.now(),
|
"published" => Timex.now(),
|
||||||
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
"to" => ["https://www.w3.org/ns/activitystreams#Public"],
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
defmodule EventosWeb.ActivityPub.ObjectView do
|
defmodule EventosWeb.ActivityPub.ObjectView do
|
||||||
use EventosWeb, :view
|
use EventosWeb, :view
|
||||||
|
alias EventosWeb.ActivityPub.ObjectView
|
||||||
alias Eventos.Service.ActivityPub.Transmogrifier
|
alias Eventos.Service.ActivityPub.Transmogrifier
|
||||||
@base %{
|
@base %{
|
||||||
"@context" => [
|
"@context" => [
|
||||||
@ -22,7 +23,7 @@ defmodule EventosWeb.ActivityPub.ObjectView do
|
|||||||
"type" => "Event",
|
"type" => "Event",
|
||||||
"id" => event.url,
|
"id" => event.url,
|
||||||
"name" => event.title,
|
"name" => event.title,
|
||||||
"category" => %{"title" => event.category.title},
|
"category" => render_one(event.category, ObjectView, "category.json", as: :category),
|
||||||
"content" => event.description,
|
"content" => event.description,
|
||||||
"mediaType" => "text/markdown",
|
"mediaType" => "text/markdown",
|
||||||
"published" => Timex.format!(event.inserted_at, "{ISO:Extended}"),
|
"published" => Timex.format!(event.inserted_at, "{ISO:Extended}"),
|
||||||
@ -32,6 +33,10 @@ defmodule EventosWeb.ActivityPub.ObjectView do
|
|||||||
end
|
end
|
||||||
|
|
||||||
def render("category.json", %{category: category}) do
|
def render("category.json", %{category: category}) do
|
||||||
category
|
%{"title" => category.title}
|
||||||
|
end
|
||||||
|
|
||||||
|
def render("category.json", %{category: nil}) do
|
||||||
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -23,6 +23,7 @@ defmodule EventosWeb.ActorView do
|
|||||||
domain: actor.domain,
|
domain: actor.domain,
|
||||||
display_name: actor.name,
|
display_name: actor.name,
|
||||||
description: actor.summary,
|
description: actor.summary,
|
||||||
|
type: actor.type,
|
||||||
# public_key: actor.public_key,
|
# public_key: actor.public_key,
|
||||||
suspended: actor.suspended,
|
suspended: actor.suspended,
|
||||||
url: actor.url,
|
url: actor.url,
|
||||||
@ -35,6 +36,7 @@ defmodule EventosWeb.ActorView do
|
|||||||
domain: actor.domain,
|
domain: actor.domain,
|
||||||
display_name: actor.name,
|
display_name: actor.name,
|
||||||
description: actor.summary,
|
description: actor.summary,
|
||||||
|
type: actor.type,
|
||||||
# public_key: actor.public_key,
|
# public_key: actor.public_key,
|
||||||
suspended: actor.suspended,
|
suspended: actor.suspended,
|
||||||
url: actor.url,
|
url: actor.url,
|
||||||
|
18
lib/eventos_web/views/bot_view.ex
Normal file
18
lib/eventos_web/views/bot_view.ex
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
defmodule EventosWeb.BotView do
|
||||||
|
use EventosWeb, :view
|
||||||
|
alias EventosWeb.BotView
|
||||||
|
|
||||||
|
def render("index.json", %{bots: bots}) do
|
||||||
|
%{data: render_many(bots, BotView, "bot.json")}
|
||||||
|
end
|
||||||
|
|
||||||
|
def render("show.json", %{bot: bot}) do
|
||||||
|
%{data: render_one(bot, BotView, "bot.json")}
|
||||||
|
end
|
||||||
|
|
||||||
|
def render("bot.json", %{bot: bot}) do
|
||||||
|
%{id: bot.id,
|
||||||
|
source: bot.source,
|
||||||
|
type: bot.type}
|
||||||
|
end
|
||||||
|
end
|
@ -34,6 +34,7 @@ defmodule EventosWeb.EventView do
|
|||||||
organizer: %{
|
organizer: %{
|
||||||
username: event.organizer_actor.preferred_username
|
username: event.organizer_actor.preferred_username
|
||||||
},
|
},
|
||||||
|
type: "Event",
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -46,6 +47,7 @@ defmodule EventosWeb.EventView do
|
|||||||
organizer: render_one(event.organizer_actor, ActorView, "acccount_basic.json"),
|
organizer: render_one(event.organizer_actor, ActorView, "acccount_basic.json"),
|
||||||
participants: render_many(event.participants, ActorView, "show_basic.json"),
|
participants: render_many(event.participants, ActorView, "show_basic.json"),
|
||||||
address: render_one(event.address, AddressView, "address.json"),
|
address: render_one(event.address, AddressView, "address.json"),
|
||||||
|
type: "Event",
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
16
lib/eventos_web/views/search_view.ex
Normal file
16
lib/eventos_web/views/search_view.ex
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
defmodule EventosWeb.SearchView do
|
||||||
|
@moduledoc """
|
||||||
|
View for Events
|
||||||
|
"""
|
||||||
|
use EventosWeb, :view
|
||||||
|
alias EventosWeb.{EventView, ActorView, GroupView, AddressView}
|
||||||
|
|
||||||
|
def render("search.json", %{events: events, actors: actors}) do
|
||||||
|
%{
|
||||||
|
data: %{
|
||||||
|
events: render_many(events, EventView, "event_simple.json"),
|
||||||
|
actors: render_many(actors, ActorView, "acccount_basic.json"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
21
lib/mix/tasks/create_bot.ex
Normal file
21
lib/mix/tasks/create_bot.ex
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
defmodule Mix.Tasks.CreateBot do
|
||||||
|
use Mix.Task
|
||||||
|
alias Eventos.Actors
|
||||||
|
alias Eventos.Actors.Bot
|
||||||
|
alias Eventos.Repo
|
||||||
|
import Logger
|
||||||
|
|
||||||
|
@shortdoc "Register user"
|
||||||
|
def run([email, name, summary, type, url]) do
|
||||||
|
Mix.Task.run("app.start")
|
||||||
|
|
||||||
|
with user <- Actors.find_by_email(email),
|
||||||
|
actor <- Actors.register_bot_account(%{name: name, summary: summary}),
|
||||||
|
{:ok, %Bot{} = bot} <- Actors.create_bot(%{"type" => type, "source" => url, "actor_id" => actor.id, "user_id" => user.id}) do
|
||||||
|
bot
|
||||||
|
|
||||||
|
else
|
||||||
|
e -> Logger.error(inspect e)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -1,6 +1,6 @@
|
|||||||
defmodule Eventos.Service.ActivityPub do
|
defmodule Eventos.Service.ActivityPub do
|
||||||
alias Eventos.Events
|
alias Eventos.Events
|
||||||
alias Eventos.Events.Event
|
alias Eventos.Events.{Event, Category}
|
||||||
alias Eventos.Service.ActivityPub.Transmogrifier
|
alias Eventos.Service.ActivityPub.Transmogrifier
|
||||||
alias Eventos.Service.WebFinger
|
alias Eventos.Service.WebFinger
|
||||||
alias Eventos.Activity
|
alias Eventos.Activity
|
||||||
@ -174,6 +174,15 @@ defmodule Eventos.Service.ActivityPub do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec find_or_make_actor_from_nickname(String.t) :: tuple()
|
||||||
|
def find_or_make_actor_from_nickname(nickname) do
|
||||||
|
with %Actor{} = actor <- Actors.get_actor_by_name(nickname) do
|
||||||
|
{:ok, actor}
|
||||||
|
else
|
||||||
|
nil -> make_actor_from_nickname(nickname)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def make_actor_from_nickname(nickname) do
|
def make_actor_from_nickname(nickname) do
|
||||||
with {:ok, %{"url" => url}} when not is_nil(url) <- WebFinger.finger(nickname) do
|
with {:ok, %{"url" => url}} when not is_nil(url) <- WebFinger.finger(nickname) do
|
||||||
make_actor_from_url(url)
|
make_actor_from_url(url)
|
||||||
@ -288,19 +297,39 @@ defmodule Eventos.Service.ActivityPub do
|
|||||||
end
|
end
|
||||||
|
|
||||||
@spec fetch_public_activities_for_actor(Actor.t, integer(), integer()) :: list()
|
@spec fetch_public_activities_for_actor(Actor.t, integer(), integer()) :: list()
|
||||||
def fetch_public_activities_for_actor(%Actor{} = actor, page \\ 10, limit \\ 10) do
|
def fetch_public_activities_for_actor(%Actor{} = actor, page \\ 1, limit \\ 10) do
|
||||||
{:ok, events, total} = Events.get_events_for_actor(actor, page, limit)
|
case actor.type do
|
||||||
activities = Enum.map(events, fn event ->
|
:Person ->
|
||||||
{:ok, activity} = event_to_activity(event)
|
{:ok, events, total} = Events.get_events_for_actor(actor, page, limit)
|
||||||
activity
|
activities = Enum.map(events, fn event ->
|
||||||
end)
|
{:ok, activity} = event_to_activity(event)
|
||||||
{activities, total}
|
activity
|
||||||
|
end)
|
||||||
|
{activities, total}
|
||||||
|
:Service ->
|
||||||
|
bot = Actors.get_bot_by_actor(actor)
|
||||||
|
case bot.type do
|
||||||
|
"ics" ->
|
||||||
|
{:ok, %HTTPoison.Response{body: body} = _resp} = HTTPoison.get(bot.source)
|
||||||
|
ical_events = body
|
||||||
|
|> ExIcal.parse()
|
||||||
|
|> ExIcal.by_range(DateTime.utc_now(), DateTime.utc_now() |> Timex.shift(years: 1))
|
||||||
|
activities = ical_events
|
||||||
|
|> Enum.chunk_every(limit)
|
||||||
|
|> Enum.at(page - 1)
|
||||||
|
|> Enum.map(fn event ->
|
||||||
|
{:ok, activity } = ical_event_to_activity(event, actor, bot.source)
|
||||||
|
activity
|
||||||
|
end)
|
||||||
|
{activities, length(ical_events)}
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp event_to_activity(%Event{} = event) do
|
defp event_to_activity(%Event{} = event, local \\ true) do
|
||||||
activity = %Activity{
|
activity = %Activity{
|
||||||
data: event,
|
data: event,
|
||||||
local: true,
|
local: local,
|
||||||
actor: event.organizer_actor.url,
|
actor: event.organizer_actor.url,
|
||||||
recipients: ["https://www.w3.org/ns/activitystreams#Public"]
|
recipients: ["https://www.w3.org/ns/activitystreams#Public"]
|
||||||
}
|
}
|
||||||
@ -309,4 +338,44 @@ defmodule Eventos.Service.ActivityPub do
|
|||||||
#stream_out(activity)
|
#stream_out(activity)
|
||||||
{:ok, activity}
|
{:ok, activity}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp ical_event_to_activity(%ExIcal.Event{} = ical_event, %Actor{} = actor, source) do
|
||||||
|
# Logger.debug(inspect ical_event)
|
||||||
|
# TODO : refactor me !
|
||||||
|
category = if is_nil ical_event.categories do
|
||||||
|
nil
|
||||||
|
else
|
||||||
|
ical_category = ical_event.categories |> hd() |> String.downcase()
|
||||||
|
case ical_category |> Events.get_category_by_title() do
|
||||||
|
nil -> case Events.create_category(%{"title" => ical_category}) do
|
||||||
|
{:ok, %Category{} = category} -> category
|
||||||
|
_ -> nil
|
||||||
|
end
|
||||||
|
category -> category
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
{:ok, event} = Events.create_event(%{
|
||||||
|
begins_on: ical_event.start,
|
||||||
|
ends_on: ical_event.end,
|
||||||
|
inserted_at: ical_event.stamp,
|
||||||
|
updated_at: ical_event.stamp,
|
||||||
|
description: ical_event.description |> sanitize_ical_event_strings,
|
||||||
|
title: ical_event.summary |> sanitize_ical_event_strings,
|
||||||
|
organizer_actor: actor,
|
||||||
|
category: category,
|
||||||
|
})
|
||||||
|
|
||||||
|
event_to_activity(event, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp sanitize_ical_event_strings(string) when is_binary(string) do
|
||||||
|
string
|
||||||
|
|> String.replace(~s"\r\n", "")
|
||||||
|
|> String.replace(~s"\\,", ",")
|
||||||
|
end
|
||||||
|
|
||||||
|
defp sanitize_ical_event_strings(nil) do
|
||||||
|
nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -81,7 +81,7 @@ defmodule Eventos.Service.WebFinger do
|
|||||||
address = "http://#{domain}/.well-known/webfinger?resource=acct:#{actor}"
|
address = "http://#{domain}/.well-known/webfinger?resource=acct:#{actor}"
|
||||||
|
|
||||||
Logger.debug(inspect address)
|
Logger.debug(inspect address)
|
||||||
with response <- HTTPoison.get!(address, [Accept: "application/json, application/activity+json, application/jrd+json"],follow_redirect: true),
|
with {:ok, %HTTPoison.Response{} = response} <- HTTPoison.get(address, [Accept: "application/json, application/activity+json, application/jrd+json"],follow_redirect: true),
|
||||||
%{status_code: status_code, body: body} when status_code in 200..299 <- response do
|
%{status_code: status_code, body: body} when status_code in 200..299 <- response do
|
||||||
{:ok, doc} = Jason.decode(body)
|
{:ok, doc} = Jason.decode(body)
|
||||||
webfinger_from_json(doc)
|
webfinger_from_json(doc)
|
||||||
|
1
mix.exs
1
mix.exs
@ -66,6 +66,7 @@ defmodule Eventos.Mixfile do
|
|||||||
{:ex_crypto, "~> 0.9.0"},
|
{:ex_crypto, "~> 0.9.0"},
|
||||||
{:http_sign, "~> 0.1.1"},
|
{:http_sign, "~> 0.1.1"},
|
||||||
{:ecto_enum, "~> 1.0"},
|
{:ecto_enum, "~> 1.0"},
|
||||||
|
{:ex_ical, github: "tcitworld/ex_ical", branch: "usable"},
|
||||||
# Dev and test dependencies
|
# Dev and test dependencies
|
||||||
{:phoenix_live_reload, "~> 1.0", only: :dev},
|
{:phoenix_live_reload, "~> 1.0", only: :dev},
|
||||||
{:ex_machina, "~> 2.1", only: :test},
|
{:ex_machina, "~> 2.1", only: :test},
|
||||||
|
1
mix.lock
1
mix.lock
@ -19,6 +19,7 @@
|
|||||||
"elixir_make": {:hex, :elixir_make, "0.4.1", "6628b86053190a80b9072382bb9756a6c78624f208ec0ff22cb94c8977d80060", [:mix], [], "hexpm"},
|
"elixir_make": {:hex, :elixir_make, "0.4.1", "6628b86053190a80b9072382bb9756a6c78624f208ec0ff22cb94c8977d80060", [:mix], [], "hexpm"},
|
||||||
"ex_crypto": {:hex, :ex_crypto, "0.9.0", "e04a831034c4d0a43fb2858f696d6b5ae0f87f07dedca3452912fd3cb5ee3ca2", [:mix], [{:poison, ">= 2.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
|
"ex_crypto": {:hex, :ex_crypto, "0.9.0", "e04a831034c4d0a43fb2858f696d6b5ae0f87f07dedca3452912fd3cb5ee3ca2", [:mix], [{:poison, ">= 2.0.0", [hex: :poison, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
"ex_doc": {:hex, :ex_doc, "0.18.3", "f4b0e4a2ec6f333dccf761838a4b253d75e11f714b85ae271c9ae361367897b7", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"},
|
"ex_doc": {:hex, :ex_doc, "0.18.3", "f4b0e4a2ec6f333dccf761838a4b253d75e11f714b85ae271c9ae361367897b7", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
|
"ex_ical": {:git, "https://github.com/tcitworld/ex_ical.git", "e2facc514ee2ce99331b6a351c00667a9b28dd01", [branch: "usable"]},
|
||||||
"ex_machina": {:hex, :ex_machina, "2.2.0", "fec496331e04fc2db2a1a24fe317c12c0c4a50d2beb8ebb3531ed1f0d84be0ed", [:mix], [{:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
|
"ex_machina": {:hex, :ex_machina, "2.2.0", "fec496331e04fc2db2a1a24fe317c12c0c4a50d2beb8ebb3531ed1f0d84be0ed", [:mix], [{:ecto, "~> 2.1", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
|
||||||
"ex_unit_notifier": {:hex, :ex_unit_notifier, "0.1.4", "36a2dcab829f506e01bf17816590680dd1474407926d43e64c1263e627c364b8", [:mix], [], "hexpm"},
|
"ex_unit_notifier": {:hex, :ex_unit_notifier, "0.1.4", "36a2dcab829f506e01bf17816590680dd1474407926d43e64c1263e627c364b8", [:mix], [], "hexpm"},
|
||||||
"excoveralls": {:hex, :excoveralls, "0.8.2", "b941a08a1842d7aa629e0bbc969186a4cefdd035bad9fe15d43aaaaaeb8fae36", [:mix], [{:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:hackney, ">= 0.12.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
|
"excoveralls": {:hex, :excoveralls, "0.8.2", "b941a08a1842d7aa629e0bbc969186a4cefdd035bad9fe15d43aaaaaeb8fae36", [:mix], [{:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:hackney, ">= 0.12.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
|
||||||
|
18
priv/repo/migrations/20180522133844_add_bots_table.exs
Normal file
18
priv/repo/migrations/20180522133844_add_bots_table.exs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
defmodule Eventos.Repo.Migrations.AddBotsTable do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def up do
|
||||||
|
create table(:bots) do
|
||||||
|
add :source, :string, null: false
|
||||||
|
add :type, :string, default: "ics"
|
||||||
|
add :actor_id, references(:actors, on_delete: :delete_all), null: false
|
||||||
|
add :user_id, references(:users, on_delete: :delete_all), null: false
|
||||||
|
|
||||||
|
timestamps()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
drop table(:bots)
|
||||||
|
end
|
||||||
|
end
|
67
test/eventos/actors/actors_test.exs
Normal file
67
test/eventos/actors/actors_test.exs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
defmodule Eventos.ActorsTest do
|
||||||
|
use Eventos.DataCase
|
||||||
|
|
||||||
|
alias Eventos.Actors
|
||||||
|
|
||||||
|
describe "bots" do
|
||||||
|
alias Eventos.Actors.Bot
|
||||||
|
|
||||||
|
@valid_attrs %{source: "some source", type: "some type"}
|
||||||
|
@update_attrs %{source: "some updated source", type: "some updated type"}
|
||||||
|
@invalid_attrs %{source: nil, type: nil}
|
||||||
|
|
||||||
|
def bot_fixture(attrs \\ %{}) do
|
||||||
|
{:ok, bot} =
|
||||||
|
attrs
|
||||||
|
|> Enum.into(@valid_attrs)
|
||||||
|
|> Actors.create_bot()
|
||||||
|
|
||||||
|
bot
|
||||||
|
end
|
||||||
|
|
||||||
|
test "list_bots/0 returns all bots" do
|
||||||
|
bot = bot_fixture()
|
||||||
|
assert Actors.list_bots() == [bot]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "get_bot!/1 returns the bot with given id" do
|
||||||
|
bot = bot_fixture()
|
||||||
|
assert Actors.get_bot!(bot.id) == bot
|
||||||
|
end
|
||||||
|
|
||||||
|
test "create_bot/1 with valid data creates a bot" do
|
||||||
|
assert {:ok, %Bot{} = bot} = Actors.create_bot(@valid_attrs)
|
||||||
|
assert bot.source == "some source"
|
||||||
|
assert bot.type == "some type"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "create_bot/1 with invalid data returns error changeset" do
|
||||||
|
assert {:error, %Ecto.Changeset{}} = Actors.create_bot(@invalid_attrs)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "update_bot/2 with valid data updates the bot" do
|
||||||
|
bot = bot_fixture()
|
||||||
|
assert {:ok, bot} = Actors.update_bot(bot, @update_attrs)
|
||||||
|
assert %Bot{} = bot
|
||||||
|
assert bot.source == "some updated source"
|
||||||
|
assert bot.type == "some updated type"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "update_bot/2 with invalid data returns error changeset" do
|
||||||
|
bot = bot_fixture()
|
||||||
|
assert {:error, %Ecto.Changeset{}} = Actors.update_bot(bot, @invalid_attrs)
|
||||||
|
assert bot == Actors.get_bot!(bot.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "delete_bot/1 deletes the bot" do
|
||||||
|
bot = bot_fixture()
|
||||||
|
assert {:ok, %Bot{}} = Actors.delete_bot(bot)
|
||||||
|
assert_raise Ecto.NoResultsError, fn -> Actors.get_bot!(bot.id) end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "change_bot/1 returns a bot changeset" do
|
||||||
|
bot = bot_fixture()
|
||||||
|
assert %Ecto.Changeset{} = Actors.change_bot(bot)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
81
test/eventos_web/controllers/bot_controller_test.exs
Normal file
81
test/eventos_web/controllers/bot_controller_test.exs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
defmodule EventosWeb.BotControllerTest do
|
||||||
|
use EventosWeb.ConnCase
|
||||||
|
|
||||||
|
alias Eventos.Actors
|
||||||
|
alias Eventos.Actors.Bot
|
||||||
|
|
||||||
|
@create_attrs %{source: "some source", type: "some type"}
|
||||||
|
@update_attrs %{source: "some updated source", type: "some updated type"}
|
||||||
|
@invalid_attrs %{source: nil, type: nil}
|
||||||
|
|
||||||
|
def fixture(:bot) do
|
||||||
|
{:ok, bot} = Actors.create_bot(@create_attrs)
|
||||||
|
bot
|
||||||
|
end
|
||||||
|
|
||||||
|
setup %{conn: conn} do
|
||||||
|
{:ok, conn: put_req_header(conn, "accept", "application/json")}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "index" do
|
||||||
|
test "lists all bots", %{conn: conn} do
|
||||||
|
conn = get conn, bot_path(conn, :index)
|
||||||
|
assert json_response(conn, 200)["data"] == []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "create bot" do
|
||||||
|
test "renders bot when data is valid", %{conn: conn} do
|
||||||
|
conn = post conn, bot_path(conn, :create), bot: @create_attrs
|
||||||
|
assert %{"id" => id} = json_response(conn, 201)["data"]
|
||||||
|
|
||||||
|
conn = get conn, bot_path(conn, :show, id)
|
||||||
|
assert json_response(conn, 200)["data"] == %{
|
||||||
|
"id" => id,
|
||||||
|
"source" => "some source",
|
||||||
|
"type" => "some type"}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "renders errors when data is invalid", %{conn: conn} do
|
||||||
|
conn = post conn, bot_path(conn, :create), bot: @invalid_attrs
|
||||||
|
assert json_response(conn, 422)["errors"] != %{}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "update bot" do
|
||||||
|
setup [:create_bot]
|
||||||
|
|
||||||
|
test "renders bot when data is valid", %{conn: conn, bot: %Bot{id: id} = bot} do
|
||||||
|
conn = put conn, bot_path(conn, :update, bot), bot: @update_attrs
|
||||||
|
assert %{"id" => ^id} = json_response(conn, 200)["data"]
|
||||||
|
|
||||||
|
conn = get conn, bot_path(conn, :show, id)
|
||||||
|
assert json_response(conn, 200)["data"] == %{
|
||||||
|
"id" => id,
|
||||||
|
"source" => "some updated source",
|
||||||
|
"type" => "some updated type"}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "renders errors when data is invalid", %{conn: conn, bot: bot} do
|
||||||
|
conn = put conn, bot_path(conn, :update, bot), bot: @invalid_attrs
|
||||||
|
assert json_response(conn, 422)["errors"] != %{}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "delete bot" do
|
||||||
|
setup [:create_bot]
|
||||||
|
|
||||||
|
test "deletes chosen bot", %{conn: conn, bot: bot} do
|
||||||
|
conn = delete conn, bot_path(conn, :delete, bot)
|
||||||
|
assert response(conn, 204)
|
||||||
|
assert_error_sent 404, fn ->
|
||||||
|
get conn, bot_path(conn, :show, bot)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp create_bot(_) do
|
||||||
|
bot = fixture(:bot)
|
||||||
|
{:ok, bot: bot}
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user