diff --git a/README.md b/README.md index 9688b26..30726aa 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,13 @@ Este é um sistema completo de gerenciamento de eventos, permitindo que organiza - Cadastro de eventos - Cadastro de Agenda de eventos - Categorias de eventos com palavras-chave associadas +- Cadastro de Lotes +- Cadastro de Comunicados +- Cadastro de Locais de eventos +- Cadastro de Recomendações de eventos +- Verificação do usuário +- Feedback do evento +- Histórico de eventos ## Gems utilizadas @@ -24,6 +31,9 @@ Este é um sistema completo de gerenciamento de eventos, permitindo que organiza - Rspec - Capybara - Devise +- Faraday +- Timecop +- Discard ## Pré-requisitos @@ -45,6 +55,9 @@ node 16.20.2 # Execute a aplicação $ bin/setup + + # A aplicação estará disponível em + http://localhost:3003 ``` ## Como rodar testes @@ -65,29 +78,7 @@ node 16.20.2 # APIs -GET /api/v1/events - -Caso não hajam eventos cadastrados, a API retorna: -`status: 200, json: []` - -Caso contrário, a API retorna `status: 200` e todos os eventos publicados no seguinte formato: - -```json -{ - "events": [ - { - "id": 1, - "name": "Evento 1", - "description": "Descrição do evento 1", - "address": "Rua 1, 123", - "logo_url": "https://www.example.com/logo1.png", - "banner_url": "https://www.example.com/banner1.png", - "participants_limit": 100, - "event_owner": "João" - } - ] -} -``` +Para ver os endpoint acesse esse link: [Documentação da API](doc/API_README.md). ## Contribuidores diff --git a/app/controllers/announcements_controller.rb b/app/controllers/announcements_controller.rb index 1d4cd0c..1999f3a 100644 --- a/app/controllers/announcements_controller.rb +++ b/app/controllers/announcements_controller.rb @@ -4,10 +4,12 @@ class AnnouncementsController < ApplicationController before_action :set_event before_action :check_if_published before_action :check_if_event_manager, only: [ :create ] + add_breadcrumb "Home", :dashboard_path + def index - @announcements = @event.announcements + @announcements = @event.announcements.order(created_at: :desc) @announcement = Announcement.new add_breadcrumb "#{@event.name}", Proc.new { event_path(@event) } diff --git a/app/controllers/schedules_controller.rb b/app/controllers/schedules_controller.rb index 0ac182d..661de70 100644 --- a/app/controllers/schedules_controller.rb +++ b/app/controllers/schedules_controller.rb @@ -7,7 +7,8 @@ class SchedulesController < ApplicationController def show @schedule = Schedule.find_by(id: params[:id]) - @schedule_items = @schedule.schedule_items.order(start_time: :desc) + @schedule_items = @schedule.schedule_items.order(start_time: :asc) + add_breadcrumb "#{@event.name}", Proc.new { event_path(@event) } add_breadcrumb "Agenda de #{I18n.l(@schedule.date.to_date, format: :short)}" diff --git a/app/views/announcements/index.html.erb b/app/views/announcements/index.html.erb index 6af143a..165d8f4 100644 --- a/app/views/announcements/index.html.erb +++ b/app/views/announcements/index.html.erb @@ -1,3 +1,4 @@ +
<%= form_with model: [@event, @announcement], local: true do |f| %>

<%= t('.title')%>

@@ -15,7 +16,7 @@ <% @announcements.each do |a|%>

<%= l a.created_at, format: :short%>

-

<%= a.title%>

+

<%= a.title%>

<%= render layout: 'layouts/action_text/contents/content' do %> <%= a.description %> @@ -25,5 +26,7 @@ <% end %> +
+ diff --git a/app/views/events/_form.html.erb b/app/views/events/_form.html.erb index 2a4f3e0..ea93ccc 100644 --- a/app/views/events/_form.html.erb +++ b/app/views/events/_form.html.erb @@ -52,7 +52,7 @@
<%= f.label :start_date, class: 'input_label' %> - <%= f.date_field :start_date, class: "input" %> + <%= f.datetime_field :start_date, class: "input" %> <% if event.errors[:start_date].any? %> <% event.errors.full_messages_for(:start_date).each do |e| %> <%= e %> @@ -62,7 +62,7 @@
<%= f.label :end_date, class: 'input_label' %> - <%= f.date_field :end_date, class: "input" %> + <%= f.datetime_field :end_date, class: "input" %> <% if event.errors[:end_date].any? %> <% event.errors.full_messages_for(:end_date).each do |e| %> <%= e %> diff --git a/app/views/events/show.html.erb b/app/views/events/show.html.erb index b4c812a..9c10cd0 100644 --- a/app/views/events/show.html.erb +++ b/app/views/events/show.html.erb @@ -1,3 +1,4 @@ +
<% if @event.logo.attached? %> @@ -38,30 +39,22 @@
<% end %> -

- Status: +

+

<% if @event.draft? %> <%= Event.human_enum_name(:status, @event.status)%> 🏷️ <% else %> <%= Event.human_enum_name(:status, @event.status)%> ✅ <% end %> -

+

+

<%= Event.human_enum_name(:event_type, @event.event_type)%>

+

Limite de Participantes: <%= @event.participants_limit %>

- -
- Descrição: - <%= render layout: 'layouts/action_text/contents/content' do %> - <%= @event.description %> - <% end %> -
- -

Evento <%= Event.human_enum_name(:event_type, @event.event_type)%>

-

Site do Evento: <%= @event.url %> @@ -73,14 +66,21 @@ <%= @event.address %>

<% end %> + +
+ <%= render layout: 'layouts/action_text/contents/content' do %> + <%= @event.description %> + <% end %> +
-
\ No newline at end of file + +
\ No newline at end of file diff --git a/app/views/schedules/show.html.erb b/app/views/schedules/show.html.erb index e62ce7f..f5d1fe9 100644 --- a/app/views/schedules/show.html.erb +++ b/app/views/schedules/show.html.erb @@ -29,7 +29,7 @@
-

<%= item.name %>

+

<%= item.name %>

Responsável:<%= item.responsible_name %>

<% else %> @@ -39,7 +39,7 @@
-

<%= item.name %>

+

<%= item.name %>

<% end %> diff --git a/db/seeds.rb b/db/seeds.rb index 39af9ad..0d4e605 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1,17 +1,3 @@ -# readme md -> rails db:drop -> rails db:migrate -> rails db:seed -puts 'Apagando todos os dados...' -Speaker.destroy_all -ScheduleItem.destroy_all -Schedule.destroy_all -TicketBatch.destroy_all -CategoryKeyword.destroy_all -Keyword.destroy_all -EventCategory.destroy_all -Announcement.destroy_all -Event.destroy_all -Category.destroy_all -User.destroy_all - puts 'Criando DOIS usuários do tipo ADMINISTRADOR...' FactoryBot.create(:user, :admin) FactoryBot.create(:user, :admin, name: 'Kleber', family_name: 'Renan', registration_number: CPF.generate, email: 'kleber@meuevento.com.br', password: 'password123') @@ -24,6 +10,7 @@ ruby_category = FactoryBot.create(:category, name: 'Ruby') programacao_category = FactoryBot.create(:category, name: 'Programação') javascript_category = FactoryBot.create(:category, name: 'JavaScript') +cloud_category = FactoryBot.create(:category, name: 'Nuvem') FactoryBot.create(:category, name: 'Java') FactoryBot.create(:category, name: 'C#') @@ -74,6 +61,30 @@ sleep(5) javascript_event.banner.attach(io: File.open(Rails.root.join('spec/support/images/banner_javascript.png')), filename: 'banner_javascript.png') +puts 'Criando evento AWS' +aws_event = FactoryBot.create(:event, + name: 'AWS re:Invent', + event_type: :online, + participants_limit: 20, + url: 'reinvent.awsevents.com', + status: :published, + user: joao_user, + categories: [ cloud_category ], + start_date: 2.minute.from_now, + end_date: 4.minutes.from_now, + description: ActionText::Content.new("

Uma semana incrível para aprender fazendo

De palestras interessantes a sessões e conexões de mudança de carreira, o re:Invent 2024 foi um sucesso incrível – e mal podemos esperar para fazê-lo novamente. As inscrições para o re:Invent 2025 abrem neste verão.


decoration
") +) +aws_event.logo.attach(io: File.open(Rails.root.join('spec/support/images/logo_aws.png')), filename: 'logo_aws.png') +sleep(5) +aws_event.banner.attach(io: File.open(Rails.root.join('spec/support/images/banner_aws.jpg')), filename: 'banner_aws.jpg') +aws_event.update_columns(start_date: 4.days.ago, end_date: 1.day.ago, code: 'ABCD1234') +aws_event.schedules.first.update_columns(date: 4.days.ago) +(1..3).each do |d| + schedule = aws_event.schedules.create(date: 1.day.from_now) + schedule.update_columns(date: d.days.ago) +end + + puts 'Criando evento TROPICAL ON RAILS...' tropical_event = FactoryBot.create(:event, name: 'Tropical on Rails 2025', @@ -84,13 +95,14 @@ status: :published, user: joao_user, categories: [ ruby_category ], - start_date: 10.minute.from_now, - end_date: 1.weeks.from_now, - description: "O Tropical on Rails 2025 é a Conferência Latam de Rails e tem como objetivo fortalecer a comunidade de Rails da América Latina para que ela continue sendo uma parte integral do presente e do futuro do Ruby on Rails. O que antes era bom como Tropical.rb agora ficou melhor ainda sendo Tropical On Rails, nossa estrutura também cresceu e nessa edição vamos ter 700 com palestrantes incríveis estarão no nosso palco: Xavier Noria, Chris Oliver, Rosa Gutiérrez, Irina Nazarova, Rafael França, Vinicius Stock e muitos outros." + start_date: Time.now, + end_date: 1.day.from_now, + description: ActionText::Content.new('

O Tropical on Rails 2025 é a Conferência Latam de Rails e tem como objetivo fortalecer a comunidade de Rails da América Latina para que ela continue sendo uma parte integral do presente e do futuro do Ruby on Rails.


O que antes era bom como Tropical.rb agora ficou melhor ainda sendo Tropical On Rails, nossa estrutura também cresceu e nessa edição vamos ter 700 participantes com palestrantes incríveis estarão no nosso palco:


Xavier Noria, Chris Oliver, Rosa Gutiérrez, Irina Nazarova, Rafael França, Vinicius Stock e muitos outros.



plateia
') ) tropical_event.logo.attach(io: File.open(Rails.root.join('spec/support/images/logo.jpg')), filename: 'logo.jpg') sleep(5) tropical_event.banner.attach(io: File.open(Rails.root.join('spec/support/images/banner.png')), filename: 'banner.png') +tropical_event.update_columns(code: 'EFGH1234') puts 'Criando evento RUBY SUMMIT BRASIL 2025...' ruby_summit_event = FactoryBot.create(:event, @@ -99,12 +111,12 @@ address: 'Teatro Renaissance - São Paulo, SP', participants_limit: 30, url: 'www.rubysummitbr.com', - status: :published, user: maria_user, categories: [ ruby_category ], start_date: 1.month.from_now, end_date: (1.month.from_now + 1.day), - description: "O Ruby Summit Brasil 2025 reúne a comunidade Ruby brasileira em um evento repleto de palestras, painéis e workshops com os melhores especialistas do mercado. Com keynotes internacionais e espaço para networking, é a oportunidade ideal para aprender e compartilhar conhecimento sobre Ruby e suas tecnologias relacionadas." + description: "O Ruby Summit Brasil 2025 reúne a comunidade Ruby brasileira em um evento repleto de palestras, painéis e workshops com os melhores especialistas do mercado. Com keynotes internacionais e espaço para networking, é a oportunidade ideal para aprender e compartilhar conhecimento sobre Ruby e suas tecnologias relacionadas.", + banner: nil ) ruby_summit_event.logo.attach(io: File.open(Rails.root.join('spec/support/images/ruby-summit-brasil.png')), filename: 'ruby-summit-brasil.png') sleep(5) @@ -116,21 +128,24 @@ address: nil, participants_limit: 30, url: 'www.fullstackconf.com', - status: :published, user: maria_user, categories: [ ruby_category, javascript_category ], start_date: 3.months.from_now, end_date: (3.months.from_now + 2.days), - description: "A Full Stack Conf 2025 é o evento definitivo para desenvolvedores full stack, abordando as principais tendências e tecnologias do mercado. Com palestras sobre Ruby, JavaScript, DevOps, arquitetura de software e mais, reunimos especialistas e profissionais de todo o mundo para compartilhar insights e experiências." + description: "A Full Stack Conf 2025 é o evento definitivo para desenvolvedores full stack, abordando as principais tendências e tecnologias do mercado. Com palestras sobre Ruby, JavaScript, DevOps, arquitetura de software e mais, reunimos especialistas e profissionais de todo o mundo para compartilhar insights e experiências.", + logo: nil ) full_stack_conf_event.banner.attach(io: File.open(Rails.root.join('spec/support/images/banner_fullstackconf.png')), filename: 'banner_fullstackconf.png') puts 'Criando PRIMEIRO LOTE de ingressos para CADA evento...' -FactoryBot.create(:ticket_batch, name: 'Primeiro Lote - Inteira', tickets_limit: 10, event: ruby_event, start_date: 1.weeks.from_now, end_date: 2.weeks.from_now, discount_option: :no_discount) -FactoryBot.create(:ticket_batch, name: 'Primeiro Lote - Inteira', tickets_limit: 10, event: javascript_event, start_date: 1.weeks.from_now, end_date: 2.weeks.from_now, discount_option: :no_discount) +FactoryBot.create(:ticket_batch, name: 'Primeiro Lote - Inteira', tickets_limit: 10, event: javascript_event, start_date: 1.day.ago, end_date: 2.weeks.from_now, discount_option: :no_discount) FactoryBot.create(:ticket_batch, name: 'Primeiro Lote - Inteira', tickets_limit: 10, event: tropical_event, start_date: 1.week.ago, end_date: 3.minutes.from_now, discount_option: :no_discount) -FactoryBot.create(:ticket_batch, name: 'Primeiro Lote - Inteira', tickets_limit: 10, event: ruby_summit_event, start_date: 1.weeks.from_now, end_date: 2.weeks.from_now, discount_option: :no_discount) -FactoryBot.create(:ticket_batch, name: 'Primeiro Lote - Inteira', tickets_limit: 10, event: full_stack_conf_event, start_date: 1.weeks.from_now, end_date: 2.weeks.from_now, discount_option: :no_discount) +FactoryBot.create(:ticket_batch, name: 'Primeiro Lote - Inteira', tickets_limit: 10, event: ruby_summit_event, start_date: 1.day.ago, end_date: 2.weeks.from_now, discount_option: :no_discount) +FactoryBot.create(:ticket_batch, name: 'Primeiro Lote - Inteira', tickets_limit: 10, event: full_stack_conf_event, start_date: 1.day.ago, end_date: 2.weeks.from_now, discount_option: :no_discount) +aws_event_batch = FactoryBot.create(:ticket_batch, name: 'Primeiro Lote - Inteira', tickets_limit: 10, event: aws_event, start_date: 2.week.ago, end_date: 1.week.ago, discount_option: :no_discount) +aws_event_batch.update_columns(code: 'ABCD1234') +tropical_event_batch = FactoryBot.create(:ticket_batch, name: 'Primeiro Lote - Inteira', tickets_limit: 10, event: tropical_event, start_date: 1.week.ago, end_date: 1.day.ago, discount_option: :no_discount) +tropical_event_batch.update_columns(code: 'EFGH1234') puts 'Criando PRIMEIRO LOTE - MEIA (PCD) de ingressos para CADA evento...' FactoryBot.create(:ticket_batch, name: 'Primeiro Lote - Meia PCD', tickets_limit: 5, event: ruby_event, start_date: 1.weeks.from_now, end_date: 2.weeks.from_now, discount_option: :disability) @@ -159,14 +174,37 @@ FactoryBot.create(:schedule_item, schedule: tropical_event.schedules.first, name: 'Paletra sobre Rails 8', description: 'Discutindo sobre as novidades que chegaram para o Rails na sua versão 8.') FactoryBot.create(:schedule_item, schedule: ruby_summit_event.schedules.first, name: 'Paletra sobre Rails', description: 'Discutindo sobre as noticias atuais do ruby no rails') FactoryBot.create(:schedule_item, schedule: full_stack_conf_event.schedules.first, name: 'Paletra sobre FullStack', description: 'Palestra do backend ao frontend') +FactoryBot.create(:schedule_item, schedule: aws_event.schedules.order(date: :asc).first, name: 'Keynote de Abertura', description: 'Abertura oficial do evento com as últimas inovações e tendências em computação em nuvem.', start_time: (Time.now).change(hour: 9, min: 0, sec: 0), end_time: (Time.now).change(hour: 9, min: 45, sec: 0), responsible_name: 'Adam Selipsky', responsible_email: 'adam@email.com') puts 'Criando SEGUNDO item de agenda para CADA evento...' FactoryBot.create(:schedule_item, schedule: ruby_event.schedules.first, name: 'Palestra sobre as vantagens do Ruby', description: 'Discutindo e comparando Ruby com outras linguagens de programação.', start_time: (Time.now).change(hour: 10, min: 0, sec: 0), end_time: (Time.now).change(hour: 11, min: 0, sec: 0), responsible_name: 'Marcos', responsible_email: 'marcos@email.com') FactoryBot.create(:schedule_item, schedule: javascript_event.schedules.first, name: 'Palestra sobre Bun', description: 'Palestra sobre tudo do Bun', start_time: (Time.now).change(hour: 10, min: 0, sec: 0), end_time: (Time.now).change(hour: 11, min: 0, sec: 0), responsible_name: 'Marcos', responsible_email: 'marcos@email.com') FactoryBot.create(:schedule_item, schedule: tropical_event.schedules.first, name: 'Palestra sobre futuro do Rails', description: 'Discutindo sobre as novidades que chegarão para o Rails.', start_time: (Time.now).change(hour: 10, min: 0, sec: 0), end_time: (Time.now).change(hour: 11, min: 0, sec: 0), responsible_name: 'Marcos', responsible_email: 'marcos@email.com') - +FactoryBot.create(:schedule_item, schedule: aws_event.schedules.order(date: :asc).first, name: 'Workshop - Arquitetura Serverless na AWS', description: 'Aprenda a construir aplicações escaláveis e eficientes utilizando AWS Lambda e outros serviços serverless.', start_time: (Time.now).change(hour: 11, min: 0, sec: 0), end_time: (Time.now).change(hour: 12, min: 30, sec: 0), responsible_name: 'Jeff Barr', responsible_email: 'jeff@email.com') + +puts 'Criando item de agenda para outros dias do evento' +FactoryBot.create(:schedule_item, schedule: tropical_event.schedules.last, name: 'Como tornal um projeto Open Source um negócio', description: 'Como desenvolvedores, a codificação é a nossa zona de conforto, mas transformá-la em um negócio é outro desafio. Compartilharei minha jornada de um projeto paralelo para um negócio em tempo integral, incluindo as dificuldades, armadilhas comuns e "códigos de trapaça" úteis.', start_time: (Time.now).change(hour: 11, min: 0, sec: 0), end_time: (Time.now).change(hour: 11, min: 30, sec: 0), responsible_name: 'Adrian Marlin', responsible_email: 'adrian@email.com') +FactoryBot.create(:schedule_item, schedule: tropical_event.schedules.last, name: 'Como Começar a Criar Aplicativos Móveis Usando Rails e Turbo Native', description: 'Descubra Turbo, Turbo Native e Strada nesta palestra, onde mergulharemos em conceitos essenciais como webviews e técnicas para implantação de aplicações Rails em iOS e Android. Conheça as vantagens e desafios deste método inovador, abrindo novos horizontes para desenvolvedores Rails.', start_time: (Time.now).change(hour: 11, min: 40, sec: 0), end_time: (Time.now).change(hour: 12, min: 10, sec: 0), responsible_name: 'José Anchieta', responsible_email: 'jose@email.com') +FactoryBot.create(:schedule_item, schedule: tropical_event.schedules.last, schedule_type: :interval, name: 'Almoço', start_time: (Time.now).change(hour: 12, min: 15, sec: 0), end_time: (Time.now).change(hour: 14, min: 00, sec: 0)) +FactoryBot.create(:schedule_item, schedule: tropical_event.schedules.last, name: 'Panel - Rails Foundation AMA', description: 'Robby Russell, CEO da Planet Argon, fará perguntas enviadas pela comunidade aos representantes da Rails Foundation.', start_time: (Time.now).change(hour: 14, min: 01, sec: 0), end_time: (Time.now).change(hour: 14, min: 45, sec: 0), responsible_name: 'Robby Russell', responsible_email: 'robby@email.com') +FactoryBot.create(:schedule_item, schedule: aws_event.schedules.order(date: :asc).first, name: 'Painel - Segurança na Nuvem', description: 'Discussão sobre práticas recomendadas para proteger workloads na AWS.', start_time: (Time.now).change(hour: 15, min: 0, sec: 0), end_time: (Time.now).change(hour: 15, min: 45, sec: 0), responsible_name: 'Merritt Baer', responsible_email: 'merritt@email.com') +FactoryBot.create(:schedule_item, schedule: aws_event.schedules.order(date: :asc).first, name: 'Networking e Happy Hour', description: 'Conecte-se com especialistas e participantes para trocar experiências sobre o mundo da nuvem.', start_time: (Time.now).change(hour: 18, min: 0, sec: 0), end_time: (Time.now).change(hour: 20, min: 0, sec: 0), responsible_name: 'Equipe AWS', responsible_email: 'contact@email.com') +FactoryBot.create(:schedule_item, schedule: aws_event.schedules.order(date: :asc).second, name: 'Deep Dive - Inteligência Artificial na AWS', description: 'Exploração avançada dos serviços de IA/ML na AWS, incluindo Amazon SageMaker.', start_time: (Time.now).change(hour: 9, min: 30, sec: 0), end_time: (Time.now).change(hour: 10, min: 30, sec: 0), responsible_name: 'Swami Sivasubramanian', responsible_email: 'swami@email.com') +FactoryBot.create(:schedule_item, schedule: aws_event.schedules.order(date: :asc).second, name: 'Workshop - Kubernetes no AWS EKS', description: 'Implementação e gerenciamento eficiente de clusters Kubernetes com Amazon EKS.', start_time: (Time.now).change(hour: 11, min: 15, sec: 0), end_time: (Time.now).change(hour: 12, min: 45, sec: 0), responsible_name: 'Abby Fuller', responsible_email: 'abby@email.com') +FactoryBot.create(:schedule_item, schedule: aws_event.schedules.order(date: :asc).second, name: 'Painel - FinOps na AWS', description: 'Melhores práticas para otimização de custos na nuvem sem comprometer a performance.', start_time: (Time.now).change(hour: 14, min: 0, sec: 0), end_time: (Time.now).change(hour: 14, min: 45, sec: 0), responsible_name: 'J.R. Storment', responsible_email: 'jr@email.com') +FactoryBot.create(:schedule_item, schedule: aws_event.schedules.order(date: :asc).second, name: 'AWS re:Play - Festa oficial', description: 'Uma noite de entretenimento e networking para encerrar o segundo dia do evento.', start_time: (Time.now).change(hour: 19, min: 0, sec: 0), end_time: (Time.now).change(hour: 23, min: 0, sec: 0), responsible_name: 'Equipe AWS', responsible_email: 'contact@email.com') +FactoryBot.create(:schedule_item, schedule: aws_event.schedules.order(date: :asc).third, name: 'Keynote - Futuro da Computação em Nuvem', description: 'Uma visão das inovações que estão moldando o futuro da AWS e da nuvem.', start_time: (Time.now).change(hour: 9, min: 0, sec: 0), end_time: (Time.now).change(hour: 9, min: 45, sec: 0), responsible_name: 'Peter DeSantis', responsible_email: 'peter@email.com') +FactoryBot.create(:schedule_item, schedule: aws_event.schedules.order(date: :asc).third, name: 'Workshop - Data Lakes e Analytics na AWS', description: 'Aprenda a construir um data lake escalável utilizando AWS Glue, Athena e Redshift.', start_time: (Time.now).change(hour: 11, min: 0, sec: 0), end_time: (Time.now).change(hour: 12, min: 30, sec: 0), responsible_name: 'Danilo Poccia', responsible_email: 'danilo@email.com') +FactoryBot.create(:schedule_item, schedule: aws_event.schedules.order(date: :asc).third, name: 'Painel - ESG e Sustentabilidade na Nuvem', description: 'Como a AWS está ajudando empresas a serem mais sustentáveis com soluções cloud.', start_time: (Time.now).change(hour: 14, min: 30, sec: 0), end_time: (Time.now).change(hour: 15, min: 15, sec: 0), responsible_name: 'Connie Hensler', responsible_email: 'connie@email.com') +FactoryBot.create(:schedule_item, schedule: aws_event.schedules.order(date: :asc).third, name: 'AWS GameDay - Desafio ao vivo', description: 'Participe de um desafio prático e demonstre suas habilidades resolvendo problemas reais na AWS.', start_time: (Time.now).change(hour: 17, min: 0, sec: 0), end_time: (Time.now).change(hour: 19, min: 0, sec: 0), responsible_name: 'Equipe AWS', responsible_email: 'gameday@email.com') +FactoryBot.create(:schedule_item, schedule: aws_event.schedules.order(date: :asc).fourth, name: 'Keynote de Encerramento', description: 'Reflexão sobre os aprendizados do evento e próximos passos na jornada AWS.', start_time: (Time.now).change(hour: 9, min: 0, sec: 0), end_time: (Time.now).change(hour: 9, min: 45, sec: 0), responsible_name: 'Werner Vogels', responsible_email: 'werner@email.com') +FactoryBot.create(:schedule_item, schedule: aws_event.schedules.order(date: :asc).fourth, name: 'Workshop - Automação e DevOps com AWS', description: 'Explore práticas avançadas de automação usando AWS CDK, CloudFormation e Terraform.', start_time: (Time.now).change(hour: 11, min: 0, sec: 0), end_time: (Time.now).change(hour: 12, min: 30, sec: 0), responsible_name: 'Kurt Kufeld', responsible_email: 'kurt@email.com') +FactoryBot.create(:schedule_item, schedule: aws_event.schedules.order(date: :asc).fourth, name: 'Painel - Casos de Sucesso na AWS', description: 'Empresas compartilham suas histórias de inovação e transformação digital na AWS.', start_time: (Time.now).change(hour: 14, min: 0, sec: 0), end_time: (Time.now).change(hour: 14, min: 45, sec: 0), responsible_name: 'Clientes AWS', responsible_email: 'sucessos@email.com') +FactoryBot.create(:schedule_item, schedule: aws_event.schedules.order(date: :asc).fourth, name: 'Encerramento e Despedida', description: 'Última oportunidade para networking e fechamento oficial do evento.', start_time: (Time.now).change(hour: 16, min: 30, sec: 0), end_time: (Time.now).change(hour: 17, min: 30, sec: 0), responsible_name: 'Equipe AWS', responsible_email: 'contact@email.com') puts 'Adicionando Comunicados...' FactoryBot.create(:announcement, user: joao_user, event: tropical_event, title: '📢 Comunicado Importante Tropical Rails 🌴🚂', description: '
Prezados participantes,
Agradecemos por fazerem parte da Tropical Rails! 🎉 Esperamos que estejam aproveitando as palestras, workshops e as incríveis conexões que este evento proporciona.
📌 Avisos Importantes:
Próxima palestra: hotwire em ação com João – 📍 Salão de palestras ⏰ 12:30
Área de networking disponível na sala 3 para quem deseja trocar experiências com outros profissionais do setor.
Lembre-se de usar a hashtag #TropicalRails para compartilhar sua experiência nas redes sociais!
⚠️ Problemas ou dúvidas? Nossa equipe de apoio está disponível no balcão de informações e pelo WhatsApp: [inserir contato].
Aproveitem ao máximo e bons trilhos rumo à inovação! 🚆💡
Atenciosamente,
Equipe Tropical Rails
') -FactoryBot.create(:announcement, user: joao_user, event: tropical_event, title: '📢 Pegue seu adesivo exclusivo da Tropical Rails! 🌴🚂', description: '
Prezados participantes,
Para marcar sua presença na Tropical Rails, estamos distribuindo adesivos exclusivos do evento! 🎉

🎟️ Quem pode retirar? Todos os participantes credenciados
Cole no seu notebook, garrafa, caderno ou onde quiser e mostre que você faz parte dessa experiência incrível!
⚠️ Os adesivos são limitados, então garanta o seu o quanto antes!
Nos vemos pelos trilhos da inovação! 🚆✨
Atenciosamente,
Equipe Tropical Rails
') +sleep(1) +FactoryBot.create(:announcement, user: joao_user, event: tropical_event, title: '📢 Pegue seu adesivo exclusivo da Tropical Rails! 🌴🚂', description: ActionText::Content.new('
Prezados participantes,
Para marcar sua presença na Tropical Rails, estamos distribuindo adesivos exclusivos do evento! 🎉
stickers

🎟️ Quem pode retirar? Todos os participantes credenciados
Cole no seu notebook, garrafa, caderno ou onde quiser e mostre que você faz parte dessa experiência incrível!
⚠️ Os adesivos são limitados, então garanta o seu o quanto antes!
Nos vemos pelos trilhos da inovação! 🚆✨
Atenciosamente,
Equipe Tropical Rails
')) +FactoryBot.create(:announcement, user: joao_user, event: aws_event, title: 'AWS Summit 2024', description: ActionText::Content.new('

Estamos empolgados em anunciar o AWS Summit 2024! Este evento imperdível reunirá especialistas da indústria, líderes de pensamento e profissionais de TI para explorar as últimas inovações em computação em nuvem.

O que você pode esperar?

Não perca a oportunidade de expandir seus conhecimentos e se conectar com a comunidade AWS.

🔹 Inscreva-se agora e garanta sua vaga! 🔹

Pizza artesanal
')) puts 'Seeds aplicados com sucesso!' diff --git a/doc/API_README.md b/doc/API_README.md new file mode 100644 index 0000000..b504f5e --- /dev/null +++ b/doc/API_README.md @@ -0,0 +1,254 @@ +# Documentação da API + +## Índice + +- [Eventos](#eventos) +- [Palestrantes](#palestrantes) +- [Lotes de Ingressos](#lotes) +- [Comunicados](#comunicados) + +## Eventos + +#### GET /api/v1/events + +```json +{ + "events": [ + { + "id": 1, + "name": "Evento 1", + "description": "\u003Ch1\u003EDescrição do evento 1\u003C/h1\u003E", + "event_type": "inperson", + "address": "Rua dos Computadores, 125", + "logo_url": "https://www.example.com/logo1.png", + "banner_url": "https://www.example.com/banner1.png", + "participants_limit": 100, + "event_owner": "João", + "start_date": "2025-02-21T00:07:00.827-03:00", + "end_date": "2025-02-28T00:07:00.827-03:00" + } + ] +} +``` + +#### GET /api/v1/events/:code + +```json +{ + "code": "OUZ73W3S", + "name": "Conferencia JS", + "description": "Um evento maneiro de Java escrito", + "event_type": "inperson", + "address": "Rua dos Computadores, 125", + "logo_url": "http://logo.png", + "banner_url": "http://banner.png", + "participants_limit": 30, + "event_owner": "Joao", + "start_date": "2025-02-21T00:07:00.827-03:00", + "end_date": "2025-02-28T00:07:00.827-03:00", + "ticket_batches": [ + { + "id": 2, + "name": "Primeiro Lote - Inteira", + "tickets_limit": 10, + "start_date": "2025-02-06", + "end_date": "2025-02-21", + "ticket_price": "109.99", + "discount_option": "no_discount", + "event_id": 2, + "created_at": "2025-02-07T00:07:21.119-03:00", + "updated_at": "2025-02-07T00:07:21.119-03:00", + "code": "BXTU46AO" + } + ], + "schedules": [ + { + "date": "2025-02-21", + "schedule_items": [ + { + "code": "VI0PQFHV", + "name": "Paletra sobre NodeJS", + "description": "Palestra sobre tudo de NodeJS.", + "start_time": "2025-02-08T09:00:00.000-03:00", + "end_time": "2025-02-08T10:00:00.000-03:00", + "responsible_name": "José", + "responsible_email": "jose@email.com", + "schedule_type": "activity" + } + ] + } + ] +} +``` + +## Palestrantes + +### POST /api/v1/speakers + +Exemplo de corpo da requisição: + +```json +{ + "email": "palestrante@example.com" +} +``` + +Resposta: + +```json: +{ + "code": "SPEAKER123" +} +``` + +### GET /api/v1/speakers/:code/events + +```json +{ + "events": [ + { + "code": "EVENT123", + "name": "Conferencia JS", + "event_type": "online", + "description": "

Um evento maneiro de Java escrito

", + "address": "Rua dos Computadores, 125", + "logo_url": "http://logo.png", + "banner_url": "http://banner.png", + "participants_limit": 30, + "event_owner": "Joao", + "start_date": "2025-02-21T00:07:00.827-03:00", + "end_date": "2025-02-28T00:07:00.827-03:00" + } + ] +} +``` + +### /api/v1/speakers/:code/event/:event_code + +```json +{ + "code": "EVENT123", + "name": "Conferencia JS", + "event_type": "online", + "description": "

Um evento maneiro de Java escrito

", + "address": "Rua dos Computadores, 125", + "logo_url": "http://logo.png", + "banner_url": "http://banner.png", + "participants_limit": 30, + "event_owner": "Joao", + "start_date": "2025-02-21T00:07:00.827-03:00", + "end_date": "2025-02-28T00:07:00.827-03:00" +} +``` + +### GET /api/v1/speakers/:code/schedules/:event_code + +```json +{ + "schedules": [ + { + "date": "2025-02-21", + "schedule_items": [ + { + "code": "VI0PQFHV", + "name": "Paletra sobre NodeJS", + "description": "Palestra sobre tudo de NodeJS.", + "start_time": "2025-02-08T09:00:00.000-03:00", + "end_time": "2025-02-08T10:00:00.000-03:00", + "responsible_name": "José", + "responsible_email": "jose@email.com", + "schedule_type": "activity" + } + ] + } + ] +} +``` + +### GET /api/v1/speakers/:code/schedule_item/:schedule_item_code + +```json +{ + "code": "VI0PQFHV", + "name": "Paletra sobre NodeJS", + "description": "Palestra sobre tudo de NodeJS.", + "start_time": "2025-02-08T09:00:00.000-03:00", + "end_time": "2025-02-08T10:00:00.000-03:00", + "responsible_name": "José", + "responsible_email": "jose@email.com", + "schedule_type": "activity", + "event": { + "code": "ABCD1234", + "start_date": "2025-02-21T00:07:00.827-03:00", + "end_date": "2025-02-28T00:07:00.827-03:00" + } +} +``` + +## Lotes + +### GET /api/v1/events/:event_code/ticket_batches + +```json +{ + "ticket_batches": [ + { + "name": "Primeiro Lote", + "tickets_limit": 15, + "start_date": "2023-10-01", + "end_date": "2023-10-15", + "ticket_price": "500.0", + "discount_option": "student", + "event_id": 1, + "code": "ABC123" + } + ] +} +``` + +### GET /api/v1/events/:event_code/ticket_batches/:code + +```json +{ + "ticket_batch": { + "name": "Primeiro Lote", + "tickets_limit": 15, + "start_date": "2023-10-01", + "end_date": "2023-10-15", + "ticket_price": "500.0", + "discount_option": "student", + "event_id": 1, + "code": "ABC123" + } +} +``` + +## Comunicados + +### GET /api/v1/events/:event_code/announcements + +```json +{ + "announcements": [ + { + "title": "Título do Comunicado", + "description": "

Descrição do comunicado

", + "created_at": "2023-10-01T12:00:00Z", + "code": "ABC123" + } + ] +} +``` + +### GET /api/v1/events/:event_code/announcements/:code + +```json +{ + "announcement": { + "title": "Título do Comunicado", + "description": "

Descrição do comunicado

", + "created_at": "2023-10-01T12:00:00Z", + "code": "ABC123" + } +} +``` diff --git a/spec/factories/announcements.rb b/spec/factories/announcements.rb index 735f4da..1be30ba 100644 --- a/spec/factories/announcements.rb +++ b/spec/factories/announcements.rb @@ -3,5 +3,6 @@ title { "Conheça o Lolla Transfer e o Lolla Express!" } association :event association :user + description { "Veja se está perto de você" } end end diff --git a/spec/factories/events.rb b/spec/factories/events.rb index c22be8a..1115e9f 100644 --- a/spec/factories/events.rb +++ b/spec/factories/events.rb @@ -8,8 +8,8 @@ association :user start_date { (Time.now + 4.weeks) } end_date { (Time.now + 5.weeks) } - banner { File.open(Rails.root.join('spec/support/images/no_banner.png'), filename: 'no_banner.png') } - logo { File.open(Rails.root.join('spec/support/images/no_logo.png'), filename: 'no_logo.png') } + banner { File.open(Rails.root.join('spec/support/images/banner.png'), filename: 'banner.png') } + logo { File.open(Rails.root.join('spec/support/images/logo.jpg'), filename: 'logo.jpg') } categories { [ create(:category) ] } end diff --git a/spec/models/announcement_spec.rb b/spec/models/announcement_spec.rb index 80b5b53..8b7b282 100644 --- a/spec/models/announcement_spec.rb +++ b/spec/models/announcement_spec.rb @@ -10,7 +10,7 @@ end it 'falha quando descrição está vazia' do - announcement = build(:announcement, title: '') + announcement = build(:announcement, description: '') announcement.valid? expect(announcement.errors[:description]).to include 'não pode ficar em branco' diff --git a/spec/requests/api/v1/event_api_request_spec.rb b/spec/requests/api/v1/event_api_request_spec.rb index 6efabeb..1d3a8b4 100644 --- a/spec/requests/api/v1/event_api_request_spec.rb +++ b/spec/requests/api/v1/event_api_request_spec.rb @@ -14,8 +14,8 @@ start_date: (Time.now + 1.day).change(hour: 8, min: 0, sec: 0), end_date: (Time.now + 3.day).change(hour: 18, min: 0, sec: 0) ) - event.logo.attach(io: File.open('spec/support/images/logo.png'), filename: 'logo.png', content_type: 'img/png') - event.banner.attach(io: File.open('spec/support/images/banner.jpg'), filename: 'banner.png', content_type: 'img/jpg') + event.logo.attach(io: File.open('spec/support/images/logo.jpg'), filename: 'logo.jpg', content_type: 'img/png') + event.banner.attach(io: File.open('spec/support/images/banner.png'), filename: 'banner.png', content_type: 'img/jpg') event.save draft_event = create(:event, user: user, status: 'draft', name: 'Formação de Padeiros', @@ -55,8 +55,8 @@ start_date: (Time.now + 1.day).change(hour: 8, min: 0, sec: 0), end_date: (Time.now + 3.day).change(hour: 18, min: 0, sec: 0) ) - event.logo.attach(io: File.open('spec/support/images/logo.png'), filename: 'logo.png', content_type: 'img/png') - event.banner.attach(io: File.open('spec/support/images/banner.jpg'), filename: 'banner.png', content_type: 'img/jpg') + event.logo.attach(io: File.open('spec/support/images/logo.jpg'), filename: 'logo.jpg', content_type: 'img/png') + event.banner.attach(io: File.open('spec/support/images/banner.png'), filename: 'banner.png', content_type: 'img/jpg') event.save get '/api/v1/events' @@ -82,8 +82,8 @@ start_date: (Time.now + 1.day).change(hour: 8, min: 0, sec: 0), end_date: (Time.now + 3.day).change(hour: 18, min: 0, sec: 0) ) - event.logo.attach(io: File.open('spec/support/images/logo.png'), filename: 'logo.png', content_type: 'img/png') - event.banner.attach(io: File.open('spec/support/images/banner.jpg'), filename: 'banner.png', content_type: 'img/jpg') + event.logo.attach(io: File.open('spec/support/images/logo.jpg'), filename: 'logo.jpg', content_type: 'img/png') + event.banner.attach(io: File.open('spec/support/images/banner.png'), filename: 'banner.png', content_type: 'img/jpg') event.save create(:event, user: user, status: 'published', name: 'Formação de Padeiros', @@ -122,8 +122,8 @@ start_date: (Time.now + 3.day).change(hour: 8, min: 0, sec: 0), end_date: (Time.now + 4.day).change(hour: 18, min: 0, sec: 0) ) - event.logo.attach(io: File.open('spec/support/images/logo.png'), filename: 'logo.png', content_type: 'img/png') - event.banner.attach(io: File.open('spec/support/images/banner.jpg'), filename: 'banner.png', content_type: 'img/jpg') + event.logo.attach(io: File.open('spec/support/images/logo.jpg'), filename: 'logo.jpg', content_type: 'img/png') + event.banner.attach(io: File.open('spec/support/images/banner.png'), filename: 'banner.png', content_type: 'img/jpg') event.save schedule = event.schedules.first ticket_batch = create(:ticket_batch, event: event, @@ -175,8 +175,8 @@ start_date: (Time.now + 3.day).change(hour: 8, min: 0, sec: 0), end_date: (Time.now + 4.day).change(hour: 18, min: 0, sec: 0) ) - event.logo.attach(io: File.open('spec/support/images/logo.png'), filename: 'logo.png', content_type: 'img/png') - event.banner.attach(io: File.open('spec/support/images/banner.jpg'), filename: 'banner.png', content_type: 'img/jpg') + event.logo.attach(io: File.open('spec/support/images/logo.jpg'), filename: 'logo.jpg', content_type: 'img/png') + event.banner.attach(io: File.open('spec/support/images/banner.png'), filename: 'banner.png', content_type: 'img/jpg') event.save get "/api/v1/events/#{event.code}" diff --git a/spec/requests/events/user_publish_event_request_spec.rb b/spec/requests/events/user_publish_event_request_spec.rb index 5942375..2695629 100644 --- a/spec/requests/events/user_publish_event_request_spec.rb +++ b/spec/requests/events/user_publish_event_request_spec.rb @@ -28,7 +28,7 @@ event = create(:event, user: user, logo: File.open(Rails.root.join('spec/support/images/logo.jpg'), filename: 'logo.jpg'), - banner: File.open(Rails.root.join('spec/support/images/banner.jpg'), filename: 'banner.jpg') + banner: File.open(Rails.root.join('spec/support/images/banner.png'), filename: 'banner.png') ) login_as user diff --git a/spec/support/images/banner.jpg b/spec/support/images/banner.jpg deleted file mode 100644 index bc92e9a..0000000 Binary files a/spec/support/images/banner.jpg and /dev/null differ diff --git a/spec/support/images/banner_aws.jpg b/spec/support/images/banner_aws.jpg new file mode 100644 index 0000000..7046f4a Binary files /dev/null and b/spec/support/images/banner_aws.jpg differ diff --git a/spec/support/images/logo.png b/spec/support/images/logo.png deleted file mode 100644 index c9c3e8b..0000000 Binary files a/spec/support/images/logo.png and /dev/null differ diff --git a/spec/support/images/logo_aws.png b/spec/support/images/logo_aws.png new file mode 100644 index 0000000..f381601 Binary files /dev/null and b/spec/support/images/logo_aws.png differ diff --git a/spec/support/images/no_banner.png b/spec/support/images/no_banner.png deleted file mode 100644 index 28eb677..0000000 Binary files a/spec/support/images/no_banner.png and /dev/null differ diff --git a/spec/support/images/no_logo.png b/spec/support/images/no_logo.png deleted file mode 100644 index 9a30880..0000000 Binary files a/spec/support/images/no_logo.png and /dev/null differ diff --git a/spec/system/announcement/user_view_announcement_spec.rb b/spec/system/announcement/user_view_announcement_spec.rb index be8d23c..6beca78 100644 --- a/spec/system/announcement/user_view_announcement_spec.rb +++ b/spec/system/announcement/user_view_announcement_spec.rb @@ -28,6 +28,22 @@ expect(page).to have_content 'Distribuição de cartas One Piece' end + it 'e ve comunicado em ordem de horário' do + event_manager = create(:user, email: 'teste@email.com') + event = create(:event, name: 'ccxp', status: :published, user: event_manager) + create(:announcement, title: 'Distribuição de cartas One Piece', user: event_manager, event: event) + create(:announcement, title: 'Transporte da estação Luz', user: event_manager, event: event) + + login_as event_manager + visit root_path + + click_on 'Gerenciar' + click_on 'Comunicados' + + announcements = all('[data-announcement-title]') + expect(announcements.map(&:text)).to eq [ 'Transporte da estação Luz', 'Distribuição de cartas One Piece' ] + end + it 'e não vê comunicados de outro organizador' do event_manager = create(:user, email: 'teste@email.com') event = create(:event, name: 'ccxp', status: :published, user: event_manager) diff --git a/spec/system/authentication/user_edit_profile_spec.rb b/spec/system/authentication/user_edit_profile_spec.rb index bd71320..756208d 100644 --- a/spec/system/authentication/user_edit_profile_spec.rb +++ b/spec/system/authentication/user_edit_profile_spec.rb @@ -26,7 +26,7 @@ click_on 'Goulart' click_on 'Editar' fill_in 'Nome', with: 'Guimarães' - attach_file('Foto de Perfil', Rails.root.join('spec/support/images/logo.png')) + attach_file('Foto de Perfil', Rails.root.join('spec/support/images/logo.jpg')) click_on 'Concluir' expect(page).to have_content 'Guimarães' @@ -86,7 +86,7 @@ click_on 'Goulart' click_on 'Editar' fill_in 'Nome', with: 'Guimarães' - attach_file('Foto de Perfil', Rails.root.join('spec/support/images/logo.png')) + attach_file('Foto de Perfil', Rails.root.join('spec/support/images/logo.jpg')) click_on 'Concluir' expect(page).to have_content 'Guimarães' diff --git a/spec/system/events/user_creates_event_spec.rb b/spec/system/events/user_creates_event_spec.rb index 37b7008..6d6824c 100644 --- a/spec/system/events/user_creates_event_spec.rb +++ b/spec/system/events/user_creates_event_spec.rb @@ -33,10 +33,10 @@ select 'Presencial', from: 'Tipo de evento' fill_in 'Limite de participantes', with: 30 fill_in 'URL do evento', with: 'www.Lollapaluza.com' - fill_in 'Data de início', with: 1.week.from_now.strftime('%Y-%m-%d') - fill_in 'Data de fim', with: 2.weeks.from_now.strftime('%Y-%m-%d') - attach_file('Logo', Rails.root.join('spec/support/images/logo.png')) - attach_file('Banner', Rails.root.join('spec/support/images/banner.jpg')) + fill_in 'Data de início', with: 1.day.from_now.strftime('%Y-%m-%dT%H:%M') + fill_in 'Data de fim', with: 9.days.from_now.strftime('%Y-%m-%dT%H:%M') + attach_file('Logo', Rails.root.join('spec/support/images/logo.jpg')) + attach_file('Banner', Rails.root.join('spec/support/images/banner.png')) find('trix-editor').click.set('test') check 'Festa' check 'Palestra' @@ -47,8 +47,8 @@ expect(page).to have_content 'test' expect(page).to have_selector "img" expect(page).to have_content "Agendas do Evento" - within 'section' do - expect(page).to have_selector "a", count: 8 + within 'aside' do + expect(page).to have_selector "a", count: 9 end end diff --git a/spec/system/schedules/user_can_view_event_schedule_spec.rb b/spec/system/schedules/user_can_view_event_schedule_spec.rb index 7318ef1..0c914bb 100644 --- a/spec/system/schedules/user_can_view_event_schedule_spec.rb +++ b/spec/system/schedules/user_can_view_event_schedule_spec.rb @@ -35,6 +35,22 @@ expect(page).to have_content schedule_item.end_time.strftime('%H:%M') end + it 'e ve itens da agenda em ordem horário de início' do + user = create(:user) + event = create(:event, user: user) + create(:schedule_item, schedule: event.schedules.first, name: 'Abertura', start_time: (Time.now).change(hour: 12, min: 15, sec: 0), end_time: (Time.now).change(hour: 13, min: 15, sec: 0)) + create(:schedule_item, schedule: event.schedules.first, schedule_type: :interval, name: 'Almoço', start_time: (Time.now).change(hour: 13, min: 15, sec: 0), end_time: (Time.now).change(hour: 14, min: 0, sec: 0)) + create(:schedule_item, schedule: event.schedules.first, name: 'Palestra rails', start_time: (Time.now).change(hour: 14, min: 15, sec: 0), end_time: (Time.now).change(hour: 15, min: 15, sec: 0)) + login_as user + + visit root_path + click_on 'Gerenciar' + click_on "Dia #{I18n.l(event.schedules.first.date.to_date, format: :short)}" + + items = all('[data-item-name]') + expect(items.map(&:text)).to eq [ 'Abertura', 'Almoço', 'Palestra rails' ] + end + it 'e ve mensagem de que a agenda não possui atividades quando agenda esta vazia' do user = create(:user) event = create(:event, user: user)