diff --git a/lib/atomic/icon.ex b/lib/atomic/icon.ex
new file mode 100644
index 000000000..b6f2cb4f5
--- /dev/null
+++ b/lib/atomic/icon.ex
@@ -0,0 +1,68 @@
+defmodule Atomic.Icon do
+ @moduledoc """
+ A module for generating unique, GitHub-style avatars for organizations.
+
+ This module takes an organization's name as input, hashes it, and then generates
+ a 5x5 grid-based icon using a mirroring pattern. The resulting icon is saved as
+ an SVG file in the `priv/static/images` directory.
+ """
+
+ @grid_size 5
+ @cell_size 50
+
+ @doc """
+ Generates an icon for the given organization based on its name.
+
+ ## Returns
+ - The file path of the generated SVG icon.
+ """
+ def generate_icon(organization) do
+ input = organization["name"]
+ hash = :crypto.hash(:sha256, input) |> :binary.bin_to_list()
+ color = Enum.take(hash, 3)
+ grid = build_grid(hash)
+
+ svg = draw(grid, color)
+ path = "priv/static/images/#{input}.svg"
+ File.write!(path, svg)
+ path
+ end
+
+ defp build_grid(hash) do
+ hash
+ |> Enum.chunk_every(@grid_size, @grid_size, :discard)
+ |> Enum.map(&mirror/1)
+ |> List.flatten()
+ end
+
+ defp mirror(row) do
+ [a, b, c | _] = row
+ [a, b, c, b, a]
+ end
+
+ defp draw(grid, color) do
+ [r, g, b] = color
+
+ header = """
+ "
+
+ 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
+
+ ""
+ end
+ )
+
+ header <> body <> footer
+ end
+end
diff --git a/priv/fake/organizations.json b/priv/fake/organizations.json
index d5f27ae48..453eac32c 100644
--- a/priv/fake/organizations.json
+++ b/priv/fake/organizations.json
@@ -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",
@@ -226,7 +226,7 @@
},
{
"name": "PoliticUM",
- "long_name": "",
- "description": ""
+ "long_name": "PoliticUM",
+ "description": "PoliticUM"
}
]
diff --git a/priv/repo/seeds/feed.exs b/priv/repo/seeds/feed.exs
index cdc2a161f..6bab9c678 100644
--- a/priv/repo/seeds/feed.exs
+++ b/priv/repo/seeds/feed.exs
@@ -9,19 +9,68 @@ 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)
+ paragraph
+ 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)
+ paragraph
+ end
+
def run do
seed_posts()
end
@@ -35,8 +84,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
@@ -45,21 +94,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()
@@ -69,11 +120,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
diff --git a/priv/repo/seeds/organizations.exs b/priv/repo/seeds/organizations.exs
index 2aaf5fea8..7fed12cb2 100644
--- a/priv/repo/seeds/organizations.exs
+++ b/priv/repo/seeds/organizations.exs
@@ -2,6 +2,7 @@ defmodule Atomic.Repo.Seeds.Organizations do
@moduledoc """
Seeds the database with organizations.
"""
+ alias Atomic.Icon
alias Atomic.Organizations
alias Atomic.Organizations.Organization
alias Atomic.Repo
@@ -44,12 +45,33 @@ 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 = Atomic.Icon.generate_icon(organization)
+
+ 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