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 = """ + + """ + + footer = "" + + 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