Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e22a256
feat: activitys and announcements english description and titles
GuilhermePSF Feb 25, 2025
ce6290d
fix: placeholder information for orgs with missing attributes
GuilhermePSF Mar 1, 2025
5e92461
feat: text dependent of the organzation and/or activity in portuguese…
GuilhermePSF Mar 2, 2025
3efe979
feat: add github like default icon generator
GuilhermePSF Mar 4, 2025
f8d20cd
feat: new icon uploader
GuilhermePSF Mar 4, 2025
d41cf09
format
GuilhermePSF Mar 4, 2025
fc663ad
fix: improve code readability
GuilhermePSF Mar 4, 2025
094befc
docs: documentation for module icon
GuilhermePSF Mar 4, 2025
8ac3e0a
docs: remove documentation from anonymous functions
GuilhermePSF Mar 4, 2025
651a588
refactor: use join with 3 arity instead of 3 for efficiency
GuilhermePSF Mar 4, 2025
54fd52a
refactor: rename file and module remove non needed lines
GuilhermePSF Mar 13, 2025
94090a5
fix: outdated alias and function calls
GuilhermePSF Mar 15, 2025
6b6a9ef
fix: remove non needed documentation
GuilhermePSF Mar 15, 2025
69e3171
refactor: make avatar generator support multiple entities
GuilhermePSF Mar 15, 2025
8eb836b
format
GuilhermePSF Mar 15, 2025
94d5903
Merge branch 'develop' into gf/improve-seeds
GuilhermePSF Mar 16, 2025
768c44d
feat: implement options for function generate_avatar
GuilhermePSF Apr 19, 2025
3930f11
feat: update generate_avatar calls to match new options
GuilhermePSF Apr 19, 2025
e2e4b6f
fix: divide function generate_avatar into seperate function to deal w…
GuilhermePSF Apr 19, 2025
7fe4bf7
chore: format
GuilhermePSF Apr 19, 2025
cc0da31
fix: typo
GuilhermePSF Apr 22, 2025
ff73a3e
chore: rename function
GuilhermePSF Apr 22, 2025
74fd425
feat: implement pattern matching
GuilhermePSF Apr 22, 2025
f2b9e42
feat: new option handling
GuilhermePSF Apr 22, 2025
d7b695d
chore: format
GuilhermePSF Apr 22, 2025
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
63 changes: 63 additions & 0 deletions lib/atomic/generate_avatar.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
defmodule Atomic.GenerateAvatar do
@moduledoc """
A module for generating unique, GitHub-style avatars for organizations.
"""

import Phoenix.HTML

@grid_size 5
@cell_size 50

def generate_avatar(seed, output_type) do
hash = :crypto.hash(:sha256, seed) |> :binary.bin_to_list()
color = Enum.take(hash, 3)
grid = build_grid(hash)
svg = draw(grid, color)

handle_output(svg, output_type)
end

defp handle_output(svg, output) when is_binary(output), do: File.write(output, svg)

defp handle_output(svg, :svg), do: svg
defp handle_output(svg, :blob), do: :erlang.term_to_binary(svg)
defp handle_output(svg, :html), do: raw(svg)

defp handle_output(_svg, invalid) do
raise ArgumentError,
"Invalid output type: #{inspect(invalid)}. Expected one of :svg, :blob, :html, or a file path string."
end

defp build_grid(hash) do
hash
|> Enum.chunk_every(@grid_size, @grid_size, :discard)
|> Enum.map(&mirror/1)
|> List.flatten()
end

defp mirror([a, b, c | _]), do: [a, b, c, b, a]

defp draw(grid, [r, g, b]) do
header = """
<svg width="#{@grid_size * @cell_size}" height="#{@grid_size * @cell_size}" xmlns="http://www.w3.org/2000/svg">
"""

footer = "</svg>"

body =
Enum.map_join(
grid
|> Enum.with_index()
|> Enum.filter(fn {val, _} -> rem(val, 2) == 0 end),
"\n",
fn {_val, index} ->
x = rem(index, @grid_size) * @cell_size
y = div(index, @grid_size) * @cell_size

"<rect x='#{x}' y='#{y}' width='#{@cell_size}' height='#{@cell_size}' fill='rgb(#{r},#{g},#{b})' />"
end
)

header <> body <> footer
end
end
8 changes: 4 additions & 4 deletions priv/fake/organizations.json
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,8 @@
},
{
"name": "Núcleo de Estudante de Contabilidade da Universidade do Minho",
"long_name": "",
"description": ""
"long_name": "Núcleo de Estudante de Contabilidade da Universidade do Minho",
"description": "Núcleo de Estudante de Contabilidade da Universidade do Minho"
},
{
"name": "NUMERUM",
Expand All @@ -226,7 +226,7 @@
},
{
"name": "PoliticUM",
"long_name": "",
"description": ""
"long_name": "PoliticUM",
"description": "PoliticUM"
}
]
91 changes: 70 additions & 21 deletions priv/repo/seeds/feed.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,66 @@ defmodule Atomic.Repo.Seeds.Feed do
alias Atomic.Repo

@activity_titles [
"Geek Night",
"Hack Night",
"Hackathon",
"Workshop",
"Talk",
"Meetup",
"Conference",
"Seminar",
"Course",
"Bootcamp",
"Study session"
"🌌 Geek Night",
"💻 Hack Night",
"🚀 Hackathon",
"🛠️ Workshop",
"🎤 Palestra",
"🤝 Meetup",
"🌍 Conferência",
"📚 Seminário",
"🎓 Curso",
"🏋️ Bootcamp",
"📖 Sessão de Estudo"
]

@announcement_titles [
"📢 Atualização importante da comunidade estudantil!",
"🚀 Novidades emocionantes para todos os estudantes!",
"🔔 Um anúncio que não vais querer perder!",
"💡 Mantém-te informado: aqui está o que está a acontecer!",
"📅 Grandes mudanças a caminho!",
"🎉 Uma mensagem especial para os nossos membros!",
"🚨 Vamos falar: aviso importante para ti!",
"📣 Grandes oportunidades esperam por ti – lê mais aqui!",
"🌟 Aqui está o que precisas de saber!",
"🏆 Atenção, estudantes: temos algo para partilhar!"
]

def activity_description(organization, activity_title) do
activity_paragraphs = [
"O #{organization.name} preparou mais uma edição de #{activity_title}! Esta é uma excelente oportunidade para te juntares a uma comunidade dinâmica, explorando novas ideias e desenvolvendo as tuas habilidades num ambiente envolvente e colaborativo.",
"Junta-te ao #{organization.name} na próxima #{activity_title}! Um evento pensado para todos os que querem aprender, partilhar conhecimento e conectar-se com outros entusiastas da área.",
"O #{organization.name} convida-te para a #{activity_title}! Prepara-te para um momento repleto de aprendizagem, desafios estimulantes e oportunidades de networking num ambiente descontraído.",
"A #{activity_title} organizada pelo #{organization.name} está quase a chegar! Uma experiência única onde podes desenvolver novas competências e conhecer pessoas com interesses semelhantes.",
"Não percas a #{activity_title} promovida pelo #{organization.name}! Um evento pensado para criar um espaço de partilha, crescimento e inovação. Fica atento para mais detalhes e garante já a tua presença! 🚀",
"O #{organization.name} traz-te a #{activity_title}, um evento onde a aprendizagem e a diversão andam de mãos dadas. Vem descobrir novas oportunidades e expandir os teus horizontes!",
"Vem participar na #{activity_title} organizada pelo #{organization.name}! Um momento perfeito para trocares experiências, aprenderes algo novo e te conectares com a comunidade.",
"A #{activity_title} do #{organization.name} é uma oportunidade imperdível para todos os interessados em explorar novas áreas e desafios. Não fiques de fora!",
"O #{organization.name} preparou a #{activity_title} a pensar em ti! Participa neste evento e aproveita para desenvolver as tuas competências num ambiente dinâmico e inspirador.",
"Se procuras uma experiência enriquecedora, a #{activity_title} promovida pelo #{organization.name} é o evento certo para ti. Marca já na tua agenda e junta-te a nós!"
]

paragraph = Enum.random(activity_paragraphs)
end

def announcement_description(organization) do
announcement_paragraphs = [
"📢 O #{organization.name} tem novidades para ti! Fica atento, porque algo incrível está a caminho. Em breve revelamos mais detalhes!",
"🚀 Atenção, comunidade! O #{organization.name} está a preparar algo especial. Não vais querer perder esta novidade!",
"🔔 Tens acompanhado as novidades do #{organization.name}? Um anúncio importante será feito em breve. Fica ligado!",
"💡 Algo empolgante está a acontecer no #{organization.name}! Mal podemos esperar para partilhar contigo. Fica atento às nossas redes!",
"📅 O #{organization.name} tem um grande anúncio para fazer. Prepara-te para descobrir algo que vai fazer a diferença!",
"🎉 Boas notícias a caminho! O #{organization.name} está prestes a lançar uma nova iniciativa. Descobre tudo em breve!",
"🚨 O #{organization.name} tem uma surpresa reservada para ti! Mantém-te ligado para não perderes esta grande oportunidade.",
"📣 Está quase! Em breve o #{organization.name} vai anunciar algo que não vais querer perder. Fica atento!",
"🌟 A equipa do #{organization.name} tem trabalhado em algo muito especial para ti. O anúncio oficial está a chegar!",
"🏆 Uma grande novidade do #{organization.name} está prestes a ser revelada. Garante que não perdes esta oportunidade única!"
]

paragraph = Enum.random(announcement_paragraphs)
end

def run do
seed_posts()
end
Expand All @@ -35,8 +82,8 @@ defmodule Atomic.Repo.Seeds.Feed do
type = Enum.random([:activity, :announcement])

case type do
:activity -> seed_activity(Enum.random(organizations).id, i)
:announcement -> seed_announcement(Enum.random(organizations).id)
:activity -> seed_activity(Enum.random(organizations), i)
:announcement -> seed_announcement(Enum.random(organizations))
end
end

Expand All @@ -45,21 +92,23 @@ defmodule Atomic.Repo.Seeds.Feed do
end
end

def seed_activity(organization_id, i) do
def seed_activity(organization, i) do
location = %{
name: Faker.Address.city(),
url: Faker.Internet.url()
}

title = Enum.random(@activity_titles)

%{
title: Enum.random(@activity_titles),
description: Faker.Lorem.paragraph(),
title: title,
description: activity_description(organization, title),
start: build_start_date(i),
finish: build_finish_date(i),
location: location,
minimum_entries: Enum.random(1..10),
maximum_entries: Enum.random(11..20),
organization_id: organization_id,
organization_id: organization.id,
enrolled: Enum.random(0..10)
}
|> Activities.create_activity_with_post()
Expand All @@ -69,11 +118,11 @@ defmodule Atomic.Repo.Seeds.Feed do
end
end

def seed_announcement(organization_id) do
def seed_announcement(organization) do
%{
title: Faker.Lorem.sentence(),
description: Faker.Lorem.paragraph(),
organization_id: organization_id
title: Enum.random(@announcement_titles),
description: announcement_description(organization),
organization_id: organization.id
}
|> Organizations.create_announcement_with_post()
|> case do
Expand Down
39 changes: 33 additions & 6 deletions priv/repo/seeds/organizations.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ defmodule Atomic.Repo.Seeds.Organizations do
@moduledoc """
Seeds the database with organizations.
"""
alias Atomic.GenerateAvatar
alias Atomic.Organizations
alias Atomic.Organizations.Organization
alias Atomic.Repo
Expand Down Expand Up @@ -44,12 +45,38 @@ defmodule Atomic.Repo.Seeds.Organizations do
# Seed other organizations
@organizations
|> Enum.each(fn organization ->
%{
name: organization["name"],
long_name: organization["long_name"],
description: organization["description"]
}
|> Organizations.create_organization()
case Repo.get_by(Organization, name: organization["name"]) do
nil ->
{:ok, new_org} =
%{
name: organization["name"],
long_name: organization["long_name"],
description: organization["description"]
}
|> Organizations.create_organization()

logo_path = "priv/static/images/#{organization["name"]}.svg"

Atomic.GenerateAvatar.generate_avatar(
organization["name"],
logo_path
)

new_org
|> Organization.logo_changeset(%{
logo: %Plug.Upload{
path: logo_path,
content_type: "image/svg",
filename: "#{organization["name"]}.svg"
}
})
|> Repo.update!()

File.rm(logo_path)

_existing_org ->
IO.puts("Organization '#{organization["name"]}' already exists. Skipping...")
end
end)
end
end
Expand Down
Loading