Compare commits
24 Commits
fix-docker
...
master
Author | SHA1 | Date |
---|---|---|
Petko Bordjukov | deebcbc95a | |
Tocho Tochev | 5660c3ef53 | |
Petko Bordjukov | 71e8ab74da | |
Petko Bordjukov | 89dd1890fd | |
Petko Bordjukov | 1018b93b11 | |
Tocho Tochev | 8cd4a4856d | |
Tocho Tochev | 0cffe052c8 | |
Tocho Tochev | 6af2d09896 | |
Tocho Tochev | ef5935bd85 | |
Tocho Tochev | 10e68f3453 | |
Petko Bordjukov | 5bbe601110 | |
Petko Bordjukov | 89438b474b | |
Petko Bordjukov | 7a64633ac0 | |
Petko Bordjukov | 6171e484cc | |
Petko Bordjukov | 2bacd84654 | |
Petko Bordjukov | fc08089796 | |
Petko Bordjukov | 93611a3bd9 | |
Tocho Tochev | 459be53b5c | |
Tocho Tochev | bcac28d4ff | |
Tocho Tochev | 5ff505d246 | |
Tocho Tochev | 87df897fe9 | |
Tocho Tochev | d44738bf58 | |
Tocho Tochev | 486a763277 | |
Tocho Tochev | cd8c3bbcc7 |
|
@ -1,4 +0,0 @@
|
||||||
.git
|
|
||||||
*.tar.gz
|
|
||||||
*.sql
|
|
||||||
node_modules
|
|
|
@ -35,3 +35,9 @@
|
||||||
/app/assets/builds/*
|
/app/assets/builds/*
|
||||||
!/app/assets/builds/.keep
|
!/app/assets/builds/.keep
|
||||||
/public/assets
|
/public/assets
|
||||||
|
|
||||||
|
# Archives
|
||||||
|
*.tar.gz
|
||||||
|
|
||||||
|
# SQL
|
||||||
|
*.sql
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
require: standard
|
||||||
|
|
||||||
|
inherit_gem:
|
||||||
|
standard: config/base.yml
|
||||||
|
|
||||||
|
AllCops:
|
||||||
|
DisabledByDefault: true
|
|
@ -1 +1 @@
|
||||||
3.3.0
|
3.3.5
|
||||||
|
|
|
@ -2,7 +2,7 @@ language: ruby
|
||||||
dist: xenial
|
dist: xenial
|
||||||
cache: bundler
|
cache: bundler
|
||||||
rvm:
|
rvm:
|
||||||
- 2.6
|
- 3.3
|
||||||
script:
|
script:
|
||||||
- RAILS_ENV=test bundle exec rake --trace bootstrap spec
|
- RAILS_ENV=test bundle exec rake --trace bootstrap spec
|
||||||
addons:
|
addons:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# syntax = docker/dockerfile:1
|
# syntax = docker/dockerfile:1
|
||||||
|
|
||||||
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
|
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version and Gemfile
|
||||||
ARG RUBY_VERSION=3.3.0
|
ARG RUBY_VERSION=3.3.5
|
||||||
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
|
FROM registry.docker.com/library/ruby:$RUBY_VERSION-slim as base
|
||||||
|
|
||||||
# Rails app lives here
|
# Rails app lives here
|
||||||
|
@ -58,5 +58,5 @@ USER rails:rails
|
||||||
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
|
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
|
||||||
|
|
||||||
# Start the server by default, this can be overwritten at runtime
|
# Start the server by default, this can be overwritten at runtime
|
||||||
EXPOSE 3000
|
EXPOSE 80
|
||||||
CMD ["./bin/rails", "server", "--early-hints"]
|
CMD ["./bin/thrust", "./bin/rails", "server", "--early-hints"]
|
||||||
|
|
2
Gemfile
2
Gemfile
|
@ -88,3 +88,5 @@ group :test do
|
||||||
gem "database_cleaner"
|
gem "database_cleaner"
|
||||||
gem "factory_bot_rails"
|
gem "factory_bot_rails"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
gem "thruster", "~> 0.1.8"
|
||||||
|
|
|
@ -491,6 +491,7 @@ GEM
|
||||||
terminal-table (3.0.2)
|
terminal-table (3.0.2)
|
||||||
unicode-display_width (>= 1.1.1, < 3)
|
unicode-display_width (>= 1.1.1, < 3)
|
||||||
thor (1.3.0)
|
thor (1.3.0)
|
||||||
|
thruster (0.1.8)
|
||||||
tilt (2.3.0)
|
tilt (2.3.0)
|
||||||
timeout (0.4.1)
|
timeout (0.4.1)
|
||||||
tzinfo (2.0.6)
|
tzinfo (2.0.6)
|
||||||
|
@ -568,6 +569,7 @@ DEPENDENCIES
|
||||||
sprockets
|
sprockets
|
||||||
sqlite3
|
sqlite3
|
||||||
standard
|
standard
|
||||||
|
thruster (~> 0.1.8)
|
||||||
uglifier
|
uglifier
|
||||||
yaml_db
|
yaml_db
|
||||||
|
|
||||||
|
|
34
README.md
34
README.md
|
@ -1,11 +1,31 @@
|
||||||
Clarion
|
# Clarion
|
||||||
=======
|
|
||||||
|
|
||||||
A CfP automation system for OpenFest.
|
A CfP automation system for OpenFest.
|
||||||
|
|
||||||
Installation
|
## Installation
|
||||||
------------
|
|
||||||
|
|
||||||
1. `git clone https://github.com/ignisf/clarion.git`
|
### For local development
|
||||||
2. Run `bundle install; bin/rake bootstrap`
|
|
||||||
3. You can now run the rails server with `bin/rails s`
|
1. `git clone https://git.openfest.org/Site/clarion/`
|
||||||
|
2. Run `rvm install "ruby-$(cat .ruby-version)"; rvm install "ruby-$(cat .ruby-version)"`
|
||||||
|
3. Start up postgresql
|
||||||
|
4. Run `bundle install; bin/rake bootstrap`
|
||||||
|
5. You can now run the rails server with `bin/rails s`
|
||||||
|
|
||||||
|
### For production
|
||||||
|
|
||||||
|
`docker build -t clarion:latest -f Dockerfile .`
|
||||||
|
|
||||||
|
Note that the docker image contains a default user (for credentials see `db/seeds.rb`).
|
||||||
|
|
||||||
|
### docker-compose
|
||||||
|
|
||||||
|
`docker-compose up` will bring everything up on `http://127.0.0.1:3000` with production configuration.
|
||||||
|
|
||||||
|
## Initial Usage
|
||||||
|
|
||||||
|
1. Go to `http://127.0.0.1:3000/management/`
|
||||||
|
2. Login (for initial creds see `db/seeds.rb`)
|
||||||
|
3. Change the credentials
|
||||||
|
4. Create a conference.
|
||||||
|
- NB: When creating a conference make sure to use the same `domain` as the one you are currently using, otherwise nothing will be shown.
|
||||||
|
|
|
@ -3,5 +3,6 @@ class Api::ConferencesController < Api::ApplicationController
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@conferences = Conference.all
|
@conferences = Conference.all
|
||||||
|
fresh_when @conferences
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,5 +5,6 @@ class Api::EventTypesController < Api::ApplicationController
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@event_types = current_conference.event_types.includes(:translations)
|
@event_types = current_conference.event_types.includes(:translations)
|
||||||
|
fresh_when @event_types
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,6 +9,5 @@ class Api::EventsController < Api::ApplicationController
|
||||||
|
|
||||||
def halfnarp_friendly
|
def halfnarp_friendly
|
||||||
@events = current_conference.events.joins(:proposition).includes(:track, :event_type).where.not(propositions: {status: :rejected})
|
@events = current_conference.events.joins(:proposition).includes(:track, :event_type).where.not(propositions: {status: :rejected})
|
||||||
render json: @events, include: [:track, :event_type]
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,5 +5,6 @@ class Api::HallsController < Api::ApplicationController
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@halls = current_conference.halls
|
@halls = current_conference.halls
|
||||||
|
fresh_when @halls
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
class Api::SchedulesController < Api::ApplicationController
|
||||||
|
include ::CurrentConferenceAssigning
|
||||||
|
include ::PublicApiExposing
|
||||||
|
before_action :require_current_conference!
|
||||||
|
|
||||||
|
def show
|
||||||
|
@halls = Conference.last.halls.includes(:translations, slots: {approved_event: [:participants_with_personal_profiles, :proposition]})
|
||||||
|
end
|
||||||
|
end
|
|
@ -5,5 +5,7 @@ class Api::SlotsController < Api::ApplicationController
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@slots = current_conference.slots
|
@slots = current_conference.slots
|
||||||
|
|
||||||
|
fresh_when @slots
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,5 +5,6 @@ class Api::SpeakersController < Api::ApplicationController
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@speakers = PersonalProfile.joins(user: {participations: {event: :proposition}}).where(events: {id: current_conference.approved_events.pluck(:id)}, conference: current_conference).distinct
|
@speakers = PersonalProfile.joins(user: {participations: {event: :proposition}}).where(events: {id: current_conference.approved_events.pluck(:id)}, conference: current_conference).distinct
|
||||||
|
fresh_when @speakers
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,5 +5,6 @@ class Api::TracksController < Api::ApplicationController
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@tracks = current_conference.tracks.includes(:translations)
|
@tracks = current_conference.tracks.includes(:translations)
|
||||||
|
fresh_when @tracks
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -33,7 +33,8 @@ class ApplicationController < ActionController::Base
|
||||||
# TODO: make this get the domain from the database
|
# TODO: make this get the domain from the database
|
||||||
prepend_view_path "lib/initfest/views" if request.host =~ /openfest/
|
prepend_view_path "lib/initfest/views" if request.host =~ /openfest/
|
||||||
prepend_view_path "lib/initfest/views" if request.host =~ /example/
|
prepend_view_path "lib/initfest/views" if request.host =~ /example/
|
||||||
prepend_view_path "lib/initfest/views" if request.host =~ /127\.0\.0/
|
prepend_view_path "lib/initfest/views" if request.host =~ /^127\.0\.0/
|
||||||
|
prepend_view_path "lib/initfest/views" if request.host =~ /^localhost$/
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
|
@ -8,7 +8,11 @@ module Management
|
||||||
private
|
private
|
||||||
|
|
||||||
def authorize_user!
|
def authorize_user!
|
||||||
head :forbidden unless current_user.admin?
|
if params[:conference_id] && params[:conference_id].to_i < Conference.last.id
|
||||||
|
head :forbidden unless current_user.admin? && current_user.owner?
|
||||||
|
else
|
||||||
|
head :forbidden unless current_user.admin?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,6 +15,12 @@ module Management
|
||||||
@volunteer = current_conference.volunteers.find(params[:id])
|
@volunteer = current_conference.volunteers.find(params[:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@volunteer = current_conference.volunteers.find(params[:id])
|
||||||
|
@volunteer.destroy!
|
||||||
|
redirect_to management_conference_volunteers_path(conference_id: current_conference.id)
|
||||||
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@volunteer = current_conference.volunteers.find(params[:id])
|
@volunteer = current_conference.volunteers.find(params[:id])
|
||||||
|
|
||||||
|
@ -35,7 +41,7 @@ module Management
|
||||||
params.require(:volunteer).permit(:name, :picture, :email, :phone,
|
params.require(:volunteer).permit(:name, :picture, :email, :phone,
|
||||||
:tshirt_size, :tshirt_cut,
|
:tshirt_size, :tshirt_cut,
|
||||||
:food_preferences, :previous_experience,
|
:food_preferences, :previous_experience,
|
||||||
:notes, :language,
|
:notes, :language, :terms_accepted,
|
||||||
:volunteer_team_id,
|
:volunteer_team_id,
|
||||||
additional_volunteer_team_ids: [])
|
additional_volunteer_team_ids: [])
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,7 +39,7 @@ module Public
|
||||||
params.require(:volunteer).permit(
|
params.require(:volunteer).permit(
|
||||||
:name, :picture, :email, :phone, :tshirt_size, :tshirt_cut,
|
:name, :picture, :email, :phone, :tshirt_size, :tshirt_cut,
|
||||||
:food_preferences, :previous_experience, :notes, :language,
|
:food_preferences, :previous_experience, :notes, :language,
|
||||||
:volunteer_team_id
|
:terms_accepted, :volunteer_team_id,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,7 @@ class VolunteerMailer < ActionMailer::Base
|
||||||
|
|
||||||
mail(
|
mail(
|
||||||
to: @volunteer.conference.email,
|
to: @volunteer.conference.email,
|
||||||
subject: "Нов доброволец за #{@volunteer.conference.title}"
|
subject: "Нов доброволец за #{@volunteer.conference.title} - #{@volunteer.volunteer_team.name}"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ class Event < ActiveRecord::Base
|
||||||
|
|
||||||
scope :ranked, -> { where.not(ranked: nil).where.not(votes: nil) }
|
scope :ranked, -> { where.not(ranked: nil).where.not(votes: nil) }
|
||||||
scope :approved, -> { where(propositions: {status: Proposition.statuses[:approved]})}
|
scope :approved, -> { where(propositions: {status: Proposition.statuses[:approved]})}
|
||||||
|
scope :approved_joined, -> { joins(:proposition).merge(Proposition.approved) }
|
||||||
|
|
||||||
validates :conference, presence: true
|
validates :conference, presence: true
|
||||||
validates :title, presence: true, length: {maximum: 65}
|
validates :title, presence: true, length: {maximum: 65}
|
||||||
|
|
|
@ -4,7 +4,7 @@ class Proposition < ActiveRecord::Base
|
||||||
enum status: [:undecided, :approved, :rejected, :backup]
|
enum status: [:undecided, :approved, :rejected, :backup]
|
||||||
delegate :proposable_title, :proposable_type, :proposable_description, to: :proposable
|
delegate :proposable_title, :proposable_type, :proposable_description, to: :proposable
|
||||||
|
|
||||||
after_create :send_creation_notification
|
after_commit :send_creation_notification, on: [:create]
|
||||||
before_destroy :send_withdrawal_notification
|
before_destroy :send_withdrawal_notification
|
||||||
|
|
||||||
def confirm!
|
def confirm!
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
class Slot < ActiveRecord::Base
|
class Slot < ActiveRecord::Base
|
||||||
belongs_to :hall
|
belongs_to :hall
|
||||||
belongs_to :event, required: false
|
belongs_to :event, required: false
|
||||||
|
belongs_to :approved_event, -> { joins(:proposition).approved_joined }, class_name: 'Event', foreign_key: 'event_id'
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,6 +12,7 @@ class Volunteer < ActiveRecord::Base
|
||||||
validates :email, format: {with: /\A[^@]+@[^@]+\z/}, presence: true, uniqueness: {scope: :conference_id}
|
validates :email, format: {with: /\A[^@]+@[^@]+\z/}, presence: true, uniqueness: {scope: :conference_id}
|
||||||
validates :phone, presence: true, format: {with: /\A[+\- \(\)0-9]+\z/}
|
validates :phone, presence: true, format: {with: /\A[+\- \(\)0-9]+\z/}
|
||||||
validates :volunteer_team, presence: true
|
validates :volunteer_team, presence: true
|
||||||
|
validates :terms_accepted, acceptance: true
|
||||||
validate :volunteer_teams_belong_to_conference
|
validate :volunteer_teams_belong_to_conference
|
||||||
|
|
||||||
phony_normalize :phone, default_country_code: "BG"
|
phony_normalize :phone, default_country_code: "BG"
|
||||||
|
@ -24,6 +25,7 @@ class Volunteer < ActiveRecord::Base
|
||||||
before_create :assign_unique_id
|
before_create :assign_unique_id
|
||||||
before_create :assign_confirmation_token
|
before_create :assign_confirmation_token
|
||||||
after_commit :send_email_confirmation_to_volunteer, on: [:create]
|
after_commit :send_email_confirmation_to_volunteer, on: [:create]
|
||||||
|
after_commit :send_email_to_organisers, on: [:create] # technically the volunteer's email is not confirmed yet
|
||||||
|
|
||||||
def send_notification_to_volunteer
|
def send_notification_to_volunteer
|
||||||
VolunteerMailer.volunteer_notification(self).deliver_later
|
VolunteerMailer.volunteer_notification(self).deliver_later
|
||||||
|
@ -47,6 +49,10 @@ class Volunteer < ActiveRecord::Base
|
||||||
VolunteerMailer.volunteer_email_confirmation(self).deliver_later
|
VolunteerMailer.volunteer_email_confirmation(self).deliver_later
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def send_email_to_organisers
|
||||||
|
VolunteerMailer.team_notification(self).deliver_later
|
||||||
|
end
|
||||||
|
|
||||||
def volunteer_teams_belong_to_conference
|
def volunteer_teams_belong_to_conference
|
||||||
conference_volunteer_teams = conference.volunteer_teams
|
conference_volunteer_teams = conference.volunteer_teams
|
||||||
unless additional_volunteer_teams.all? { |team| conference_volunteer_teams.include? team }
|
unless additional_volunteer_teams.all? { |team| conference_volunteer_teams.include? team }
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
class VolunteerTeam < ActiveRecord::Base
|
class VolunteerTeam < ActiveRecord::Base
|
||||||
belongs_to :conference
|
belongs_to :conference
|
||||||
has_and_belongs_to_many :volunteers
|
has_many :volunteers, inverse_of: :volunteer_team
|
||||||
|
has_and_belongs_to_many :supporters, class_name: "Volunteer", inverse_of: :additional_volunteer_teams
|
||||||
|
|
||||||
validates :name, presence: true
|
validates :name, presence: true
|
||||||
validates :color, presence: true, format: {with: /\A#?[a-f0-9]{6}\z/i}
|
validates :color, presence: true, format: {with: /\A#?[a-f0-9]{6}\z/i}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
json.array! @events, cached: ->(event) { [event, event.track, event.event_type] } do |event|
|
||||||
|
json.id event.id
|
||||||
|
json.title event.title
|
||||||
|
json.abstract event.abstract
|
||||||
|
json.track_id event.track_id
|
||||||
|
|
||||||
|
json.track do
|
||||||
|
json.name event.track.name
|
||||||
|
end
|
||||||
|
json.event_type do
|
||||||
|
json.name event.event_type.name
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,22 @@
|
||||||
|
@halls.each do |hall|
|
||||||
|
json.set! hall.name do
|
||||||
|
json.days do
|
||||||
|
hall.slots.to_a.sort_by(&:starts_at).group_by { |slot| slot.starts_at.to_date }.each do |day, slots|
|
||||||
|
json.set! day do
|
||||||
|
json.array! slots do |slot|
|
||||||
|
next unless slot.approved_event
|
||||||
|
json.starts_at slot.starts_at
|
||||||
|
json.starts_at_human l(slot.starts_at, format: '%a, %H:%M')
|
||||||
|
json.title slot.approved_event.title
|
||||||
|
json.speakers do
|
||||||
|
json.array! slot.approved_event.participants_with_personal_profiles do |participant|
|
||||||
|
json.name participant.name
|
||||||
|
json.email participant.public_email
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,6 @@
|
||||||
@speakers.each do |speaker|
|
@speakers.each do |speaker|
|
||||||
json.set! speaker.user_id do
|
json.set! speaker.user_id do
|
||||||
json.extract! speaker, :twitter, :github, :biography, :public_email, :organisation, :last_name, :first_name
|
json.extract! speaker, :twitter, :github, :biography, :public_email, :organisation, :last_name, :first_name, :name
|
||||||
json.picture speaker.picture.serializable_hash
|
json.picture rails_blob_url(speaker.picture.variant(resize_to_fill: [100, 100]))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,7 +11,5 @@
|
||||||
|
|
||||||
С приложения QR код към този имейл ще можете да достъпите формуляра за обратна връзка на предложеното от Вас събитие. Моля, включете го в презентацията си.
|
С приложения QR код към този имейл ще можете да достъпите формуляра за обратна връзка на предложеното от Вас събитие. Моля, включете го в презентацията си.
|
||||||
|
|
||||||
Ако планирате да представяте отдалечено или използвате MacBook, моля, отговорете на този имейл, за да ни уведомите. Също така, ако имате въпроси или нужда от допълнителна информация, не се колебайте да се свържете с нас, като отговорите на този имейл.
|
|
||||||
|
|
||||||
Поздрави,
|
Поздрави,
|
||||||
Екипът на <%= @event.conference.title %>
|
Екипът на <%= @event.conference.title %>
|
||||||
|
|
|
@ -11,8 +11,6 @@ To confirm your participation please follow the link below as soon as you can:
|
||||||
|
|
||||||
We kindly request that you ensure the inclusion of the QR code attached to this email in your presentation. It links directly to the feedback form for your presentation, making it easier for attendees to provide valuable insights.
|
We kindly request that you ensure the inclusion of the QR code attached to this email in your presentation. It links directly to the feedback form for your presentation, making it easier for attendees to provide valuable insights.
|
||||||
|
|
||||||
Additionally, please respond to this email to let us know whether your presentation will be remote or if you plan to present using a MacBook.
|
|
||||||
|
|
||||||
Should you have any questions or require further information, please do not hesitate to contact us by replying to this email.
|
Should you have any questions or require further information, please do not hesitate to contact us by replying to this email.
|
||||||
|
|
||||||
Best regards,
|
Best regards,
|
||||||
|
|
|
@ -20,5 +20,6 @@
|
||||||
= f.input :food_preferences, collection: Volunteer::FOOD_PREFERENCES, wrapper: :horizontal_radio_and_checkboxes, as: :radio_buttons, checked: (@volunteer.food_preferences.presence || :none)
|
= f.input :food_preferences, collection: Volunteer::FOOD_PREFERENCES, wrapper: :horizontal_radio_and_checkboxes, as: :radio_buttons, checked: (@volunteer.food_preferences.presence || :none)
|
||||||
= f.input :previous_experience
|
= f.input :previous_experience
|
||||||
= f.input :notes
|
= f.input :notes
|
||||||
|
= f.input :terms_accepted
|
||||||
.panel-footer.text-right
|
.panel-footer.text-right
|
||||||
= f.submit class: 'btn btn-primary'
|
= f.submit class: 'btn btn-primary'
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<%- @volunteers.each do |volunteer| -%>
|
<%- @volunteers.each do |volunteer| -%>
|
||||||
<%= CSV.generate_line([volunteer.id,
|
<%= CSV.generate_line([volunteer.id,
|
||||||
volunteer.name,
|
volunteer.name,
|
||||||
volunteer.email,
|
"#{volunteer.confirmed_at.nil? ? '(unverified) ' : ''}#{volunteer.email}",
|
||||||
volunteer.language,
|
volunteer.language,
|
||||||
volunteer.unique_id,
|
volunteer.unique_id,
|
||||||
volunteer.phone,
|
volunteer.phone,
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
h4.media-heading
|
h4.media-heading
|
||||||
= volunteer.name
|
= volunteer.name
|
||||||
p
|
p
|
||||||
= icon(:envelope, volunteer.email)
|
= icon(volunteer.confirmed_at.present? ? "envelope" : "envelope-o", "#{volunteer.confirmed_at.nil? ? '(unverified) ' : ''}#{volunteer.email}")
|
||||||
td
|
td
|
||||||
= volunteer.volunteer_team.name
|
= volunteer.volunteer_team.name
|
||||||
td.actions
|
td.actions
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
h4 = t '.other_info'
|
h4 = t '.other_info'
|
||||||
= icon(:language, t("locales.#{@volunteer.language}"))
|
= icon(:language, t("locales.#{@volunteer.language}"))
|
||||||
br
|
br
|
||||||
= icon(:envelope, @volunteer.email)
|
= icon(@volunteer.confirmed_at.present? ? "envelope" : "envelope-o", @volunteer.email)
|
||||||
br
|
br
|
||||||
= icon(:phone, @volunteer.phone.try(:phony_formatted, format: :international))
|
= icon(:phone, @volunteer.phone.try(:phony_formatted, format: :international))
|
||||||
br
|
br
|
||||||
|
|
|
@ -1,21 +1,11 @@
|
||||||
Здравейте,
|
Здравейте,
|
||||||
|
|
||||||
<%= @volunteer.name %> <<%= @volunteer.email %>> изпрати кандидатура за доброволец.
|
Някой изпрати кандидатура за доброволец.
|
||||||
|
|
||||||
Екипи: <%= @volunteer.volunteer_teams.map(&:name).join(', ') %>
|
Екип: <%= @volunteer.volunteer_team.name %>
|
||||||
|
|
||||||
|
Връзка към профил: <%= management_conference_volunteer_url(@volunteer.conference, @volunteer) %>
|
||||||
|
|
||||||
Език: <%= @volunteer.language %>
|
Език: <%= @volunteer.language %>
|
||||||
Телефон: <%= @volunteer.phone %>
|
|
||||||
Размер на тениска: <%= @volunteer.tshirt_size %>
|
Размер на тениска: <%= @volunteer.tshirt_size %>
|
||||||
Кройка на тениска: <%= @volunteer.tshirt_cut %>
|
Кройка на тениска: <%= @volunteer.tshirt_cut %>
|
||||||
Предпочитания за храна: <%= @volunteer.food_preferences %>
|
|
||||||
<% if @volunteer.previous_experience.present? -%>
|
|
||||||
|
|
||||||
Предходен опит:
|
|
||||||
<%= @volunteer.previous_experience %>
|
|
||||||
<% end -%>
|
|
||||||
<% if @volunteer.notes.present? -%>
|
|
||||||
|
|
||||||
Бележки:
|
|
||||||
<%= @volunteer.notes %>
|
|
||||||
<% end -%>
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/usr/bin/env ruby
|
||||||
|
require "rubygems"
|
||||||
|
require "bundler/setup"
|
||||||
|
|
||||||
|
load Gem.bin_path("thruster", "thrust")
|
|
@ -79,7 +79,7 @@ test:
|
||||||
#
|
#
|
||||||
production:
|
production:
|
||||||
<<: *default
|
<<: *default
|
||||||
host: host.containers.internal
|
host: <%= ENV.fetch("CLARION_DATABASE_HOST") { "host.containers.internal" } %>
|
||||||
database: clarion
|
database: clarion
|
||||||
username: clarion
|
username: clarion
|
||||||
password: <%= ENV["CLARION_DATABASE_PASSWORD"] %>
|
password: <%= ENV["CLARION_DATABASE_PASSWORD"] %>
|
||||||
|
|
|
@ -39,7 +39,7 @@ set :linked_dirs, fetch(:linked_dirs, []).push("log", "tmp/uploads", "tmp/pids",
|
||||||
# Default value for keep_releases is 5
|
# Default value for keep_releases is 5
|
||||||
set :keep_releases, 550
|
set :keep_releases, 550
|
||||||
|
|
||||||
set :rvm_ruby_version, "2.6.5"
|
set :rvm_ruby_version, "3.3.5"
|
||||||
|
|
||||||
set :puma_bind, ["tcp://127.0.0.1:9087"]
|
set :puma_bind, ["tcp://127.0.0.1:9087"]
|
||||||
set :puma_init_active_record, true
|
set :puma_init_active_record, true
|
||||||
|
|
|
@ -46,14 +46,14 @@ Rails.application.configure do
|
||||||
|
|
||||||
# Assume all access to the app is happening through a SSL-terminating reverse proxy.
|
# Assume all access to the app is happening through a SSL-terminating reverse proxy.
|
||||||
# Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies.
|
# Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies.
|
||||||
# config.assume_ssl = true
|
config.assume_ssl = true
|
||||||
|
|
||||||
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
|
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
|
||||||
config.force_ssl = true
|
config.force_ssl = ENV["CLARION_USE_PLAINTEXT"] != "yes"
|
||||||
|
|
||||||
# Log to STDOUT by default
|
# Log to STDOUT by default
|
||||||
config.logger = ActiveSupport::Logger.new(STDOUT)
|
config.logger = ActiveSupport::Logger.new(STDOUT)
|
||||||
.tap { |logger| logger.formatter = ::Logger::Formatter.new }
|
.tap { |logger| logger.formatter = ::Logger::Formatter.new }
|
||||||
.then { |logger| ActiveSupport::TaggedLogging.new(logger) }
|
.then { |logger| ActiveSupport::TaggedLogging.new(logger) }
|
||||||
|
|
||||||
# Prepend all log lines with the following tags.
|
# Prepend all log lines with the following tags.
|
||||||
|
@ -90,7 +90,7 @@ Rails.application.configure do
|
||||||
config.action_mailer.default_options = {from: "OpenFest <cfp@openfest.org>"}
|
config.action_mailer.default_options = {from: "OpenFest <cfp@openfest.org>"}
|
||||||
config.action_mailer.default_url_options = {host: "cfp.openfest.org"}
|
config.action_mailer.default_url_options = {host: "cfp.openfest.org"}
|
||||||
config.action_mailer.smtp_settings = {
|
config.action_mailer.smtp_settings = {
|
||||||
address: "mail.openfest.org"
|
address: ENV.fetch("CLARION_MAIL_SERVER", "mail.openfest.org")
|
||||||
}
|
}
|
||||||
|
|
||||||
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
|
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
|
||||||
|
|
|
@ -118,6 +118,7 @@ bg:
|
||||||
food_preferences: Предпочитана храна
|
food_preferences: Предпочитана храна
|
||||||
previous_experience: Предишен опит
|
previous_experience: Предишен опит
|
||||||
notes: Бележки
|
notes: Бележки
|
||||||
|
terms_accepted: Съгласен съм екипът да се свързва с мен
|
||||||
language: Език
|
language: Език
|
||||||
volunteer_team: Екип доброволци
|
volunteer_team: Екип доброволци
|
||||||
additional_volunteer_teams: Допълнителни екипи доброволци
|
additional_volunteer_teams: Допълнителни екипи доброволци
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
bg:
|
||||||
|
activerecord:
|
||||||
|
attributes:
|
||||||
|
user:
|
||||||
|
confirmation_sent_at: Потвърждението е изпратено на
|
||||||
|
confirmation_token: Код за потвърждение
|
||||||
|
confirmed_at: Дата на потвърждение
|
||||||
|
created_at: Създаван на
|
||||||
|
current_password: Настояща парола
|
||||||
|
current_sign_in_at: Текущо влизане на
|
||||||
|
current_sign_in_ip: IP на текущото влизане
|
||||||
|
email: Имейл
|
||||||
|
encrypted_password: Закодирана парола
|
||||||
|
failed_attempts: Грешни опити
|
||||||
|
last_sign_in_at: Последно влизане на
|
||||||
|
last_sign_in_ip: IP на последното влизане
|
||||||
|
locked_at: Дата на заключването
|
||||||
|
password: Парола
|
||||||
|
password_confirmation: Потвърждаване на паролата
|
||||||
|
remember_created_at: Дата на създаване на запомнянето
|
||||||
|
remember_me: Запомни ме
|
||||||
|
reset_password_sent_at: Дата на изпращане на промяна на парола
|
||||||
|
reset_password_token: Код за промяна на парола
|
||||||
|
sign_in_count: Бройка входове
|
||||||
|
unconfirmed_email: Непотвърден имейл
|
||||||
|
unlock_token: Код за отключване на профил
|
||||||
|
updated_at: Последна промяна
|
||||||
|
models:
|
||||||
|
user:
|
||||||
|
one: Потребител
|
||||||
|
other: Потребители
|
||||||
|
devise:
|
||||||
|
confirmations:
|
||||||
|
confirmed: Регистрацията Ви е потвърдена.
|
||||||
|
new:
|
||||||
|
resend_confirmation_instructions: Повторно изпращане на инструкции за потвърждаване
|
||||||
|
send_instructions: Ще получите имейл с инструкции за потвърждаване на Вашата регистрация до няколко минути.
|
||||||
|
send_paranoid_instructions: Ако Вашият имейл адрес съществува в нашата база данни, ще получите имейл с инструкции за потвърждаване на Вашия профил до няколко минути.
|
||||||
|
failure:
|
||||||
|
already_authenticated: Вече сте влезли в профила си.
|
||||||
|
inactive: Профилът Ви все още не е активиран.
|
||||||
|
invalid: Грешни %{authentication_keys} или парола.
|
||||||
|
last_attempt: Имате още един опит преди акаунтът Ви да бъде заключен.
|
||||||
|
locked: Профилът Ви е заключен.
|
||||||
|
not_found_in_database: Грешни %{authentication_keys} или парола.
|
||||||
|
timeout: Сесията Ви е изтекла, моля влезте отново, за да продължите.
|
||||||
|
unauthenticated: Преди да продължите, трябва да влезете в профила си или да се регистрирате.
|
||||||
|
unconfirmed: Преди да продължите, трябва да потвърдите регистрацията си.
|
||||||
|
mailer:
|
||||||
|
confirmation_instructions:
|
||||||
|
action: Потвърждаване на профил
|
||||||
|
greeting: Добре дошли, %{recipient}!
|
||||||
|
instruction: 'Можете да потвърдите имейл адреса си чрез линка по-долу:'
|
||||||
|
subject: Инструкции за потвърждаване
|
||||||
|
email_changed:
|
||||||
|
greeting: Здравейте, %{recipient}!
|
||||||
|
message: Свързваме се с Вас, за да Ви уведомим, че имейлът Ви е сменен на %{email}.
|
||||||
|
message_unconfirmed: Свързваме се с Вас, за да Ви уведомим, че имейлът Ви се сменя на %{email}.
|
||||||
|
subject: Промяна на имейл
|
||||||
|
password_change:
|
||||||
|
greeting: Здравейте, %{recipient}!
|
||||||
|
message: Пишем Ви, за да Ви уведомим, че паролата Ви беше променена.
|
||||||
|
subject: Променена парола
|
||||||
|
reset_password_instructions:
|
||||||
|
action: Смяна на парола
|
||||||
|
greeting: Здравейте, %{recipient}!
|
||||||
|
instruction: Някой е поискал линк за промяна на паролата Ви. Можете да промените паролата си чрез линка по-долу.
|
||||||
|
instruction_2: В случай че не сте поискали промяна на паролата си, просто игнорирайте този имейл.
|
||||||
|
instruction_3: Паролата Ви няма да бъде променена, докато не използвате горния линк, за да създадете нова.
|
||||||
|
subject: Инструкции за промяна на парола
|
||||||
|
unlock_instructions:
|
||||||
|
action: Отключване на профил
|
||||||
|
greeting: Здравейте, %{recipient}!
|
||||||
|
instruction: 'Кликнете върху линка по-долу, за да отключите профила си:'
|
||||||
|
message: Профилът Ви е заключен поради надвишаване на максималния позволен брой неуспешни опити за вход.
|
||||||
|
subject: Инструкции за отключване
|
||||||
|
omniauth_callbacks:
|
||||||
|
failure: Не успяхме да ви оторизираме чрез %{kind}, защото %{reason}.
|
||||||
|
success: Успешна оторизация чрез %{kind} профил.
|
||||||
|
passwords:
|
||||||
|
edit:
|
||||||
|
change_my_password: Промяна на паролата ми
|
||||||
|
change_your_password: Променете паролата си
|
||||||
|
confirm_new_password: Потвърждение на новата парола
|
||||||
|
new_password: Нова парола
|
||||||
|
new:
|
||||||
|
forgot_your_password: Забравена парола?
|
||||||
|
send_me_reset_password_instructions: Изпрати инструкции за промяна на парола
|
||||||
|
no_token: Може да достъпите тази страница само от имейл за промяна на паролата. Ако сте отворили тази страница от такъв имейл, уверете се, че използвате целия URL-адрес, който сме Ви изпратили.
|
||||||
|
send_instructions: Ще получите имейл с инструкции как да промените паролата си до няколко минути.
|
||||||
|
send_paranoid_instructions: Ако Вашият имейл адрес съществува в базата ни, ще получите инструкции за промяна на Вашата парола.
|
||||||
|
updated: Паролата Ви е променена успешно. Влязохте успешно в профила си.
|
||||||
|
updated_not_active: Паролата Ви е променена успешно.
|
||||||
|
registrations:
|
||||||
|
destroyed: Довиждане! Вашият профил беше успешно изтрит. Надяваме се скоро да Ви видим отново.
|
||||||
|
edit:
|
||||||
|
are_you_sure: Сигурни ли сте?
|
||||||
|
cancel_my_account: Закриване на профил
|
||||||
|
currently_waiting_confirmation_for_email: 'Очаква се потвърждение за: %{email}'
|
||||||
|
leave_blank_if_you_don_t_want_to_change_it: оставете празно, ако не искате да го променяте
|
||||||
|
title: Редакция на %{resource}
|
||||||
|
unhappy: Недоволни
|
||||||
|
update: Обновяване
|
||||||
|
we_need_your_current_password_to_confirm_your_changes: въведете настоящата си парола за потвърждаване на промените
|
||||||
|
new:
|
||||||
|
sign_up: Регистрация
|
||||||
|
signed_up: Добре дошли! Вие се регистрирахте успешно.
|
||||||
|
signed_up_but_inactive: Регистрирахте се успешно. Въпреки това, не можете да влезете в профила си, защото той все още не е активиран.
|
||||||
|
signed_up_but_locked: Регистрирахте се успешно. Въпреки това, не можете да влезете в профила си, защото той е заключен.
|
||||||
|
signed_up_but_unconfirmed: Писмо с линк за потвърждаване на профила Ви беше изпратено на вашия имейл адрес. Моля, отворете линка, за да активирате Вашия профил.
|
||||||
|
update_needs_confirmation: Обновихте профила си успешно, но трябва да проверим Вашия нов имейл адрес. Моля, проверете пощата си и отворете линка за потвърждаване на новия адрес.
|
||||||
|
updated: Обновихте профила си успешно.
|
||||||
|
updated_but_not_signed_in: Вашият профил бе обновен успешно, но понеже паролата Ви беше променена, трябва да влезнете отново.
|
||||||
|
sessions:
|
||||||
|
already_signed_out: Излязохте успешно.
|
||||||
|
new:
|
||||||
|
sign_in: Вход
|
||||||
|
signed_in: Влязохте успешно.
|
||||||
|
signed_out: Излязохте успешно.
|
||||||
|
shared:
|
||||||
|
links:
|
||||||
|
back: Назад
|
||||||
|
didn_t_receive_confirmation_instructions: Не сте получили инструкции за потвърждаване?
|
||||||
|
didn_t_receive_unlock_instructions: Не сте получили инструкции за отключване?
|
||||||
|
forgot_your_password: Забравена парола?
|
||||||
|
sign_in: Вход
|
||||||
|
sign_in_with_provider: Вход с %{provider}
|
||||||
|
sign_up: Регистрация
|
||||||
|
minimum_password_length:
|
||||||
|
one: "(минимум %{count} символ)"
|
||||||
|
other: "(минимум %{count} символа)"
|
||||||
|
unlocks:
|
||||||
|
new:
|
||||||
|
resend_unlock_instructions: Повторно изпращане на инструкции за отключване
|
||||||
|
send_instructions: Ще получите имейл с инструкции как да отключите профила си до няколко минути.
|
||||||
|
send_paranoid_instructions: Ако профилът Ви съществува в базата ни, ще получите имейл с инструкции за отключването му до няколко минути.
|
||||||
|
unlocked: Профилът Ви е отключен успешно. За да продължите, моля влезте.
|
||||||
|
errors:
|
||||||
|
messages:
|
||||||
|
already_confirmed: е вече потвърден, моля опитайте да влезете в профила си
|
||||||
|
confirmation_period_expired: трябва да се потвърди в рамките на %{period}, моля направете нова заявка за потвърждаване
|
||||||
|
expired: е изтекъл, моля заявете нов
|
||||||
|
not_found: не е намерен
|
||||||
|
not_locked: не бе заключен
|
||||||
|
not_saved:
|
||||||
|
one: 'Една грешка попречи този %{resource} да бъде записан:'
|
||||||
|
other: "%{count} грешки попречиха този %{resource} да бъде записан:"
|
|
@ -118,6 +118,7 @@ en:
|
||||||
food_preferences: Food preference
|
food_preferences: Food preference
|
||||||
previous_experience: Previous experience
|
previous_experience: Previous experience
|
||||||
notes: Notes
|
notes: Notes
|
||||||
|
terms_accepted: I agree to be contacted by the team
|
||||||
language: Language
|
language: Language
|
||||||
volunteer_team: Volunteer team
|
volunteer_team: Volunteer team
|
||||||
additional_volunteer_teams: Additional volunteer teams
|
additional_volunteer_teams: Additional volunteer teams
|
||||||
|
|
|
@ -32,6 +32,7 @@ Rails.application.routes.draw do
|
||||||
resources :event_types, only: :index
|
resources :event_types, only: :index
|
||||||
resources :halls, only: :index
|
resources :halls, only: :index
|
||||||
resources :slots, only: :index
|
resources :slots, only: :index
|
||||||
|
resource :schedule, only: :show
|
||||||
resources :volunteers
|
resources :volunteers
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddTermsAcceptedToVolunteer < ActiveRecord::Migration[7.1]
|
||||||
|
def change
|
||||||
|
add_column :volunteers, :terms_accepted, :boolean, default: false
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddOwnerFieldToUsers < ActiveRecord::Migration[7.1]
|
||||||
|
def change
|
||||||
|
add_column :users, :owner, :boolean, null: false, default: false
|
||||||
|
end
|
||||||
|
end
|
|
@ -11,4 +11,5 @@ User.create(
|
||||||
password_confirmation: "123qweASD",
|
password_confirmation: "123qweASD",
|
||||||
confirmed_at: Time.current,
|
confirmed_at: Time.current,
|
||||||
admin: true
|
admin: true
|
||||||
|
owner: true
|
||||||
)
|
)
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,40 @@
|
||||||
|
services:
|
||||||
|
clarion:
|
||||||
|
build:
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
context: .
|
||||||
|
environment:
|
||||||
|
RAILS_ENV: production
|
||||||
|
CLARION_DATABASE_HOST: db
|
||||||
|
CLARION_DATABASE_PASSWORD: not-a-real-db-password-tiliez4phei9oZoo1Shoyitee2zoon8O
|
||||||
|
REDIS_URL: redis://redis:6379/1
|
||||||
|
CLARION_MAIL_SERVER: mail-dummy
|
||||||
|
CLARION_USE_PLAINTEXT: yes
|
||||||
|
SECRET_KEY_BASE: not-a-real-secret-oodeig8etho1usik5Eehoh9jah9yuS3o
|
||||||
|
ports:
|
||||||
|
- 127.0.0.1:3000:3000
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
- redis
|
||||||
|
- mail-dummy
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: postgres:16.3
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: clarion
|
||||||
|
POSTGRES_PASSWORD: not-a-real-db-password-tiliez4phei9oZoo1Shoyitee2zoon8O
|
||||||
|
POSTGRES_DB: clarion
|
||||||
|
volumes:
|
||||||
|
- pgdata:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:7
|
||||||
|
|
||||||
|
mail-dummy:
|
||||||
|
image: python:3.11-slim
|
||||||
|
command: python3 -m smtpd --debug --class DebuggingServer 0.0.0.0:25
|
||||||
|
expose:
|
||||||
|
- 25
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
pgdata:
|
|
@ -22,5 +22,6 @@
|
||||||
= f.input :food_preferences, collection: Volunteer::FOOD_PREFERENCES, as: :radio_buttons, wrapper: :default, checked: (@volunteer.food_preferences.presence || :none)
|
= f.input :food_preferences, collection: Volunteer::FOOD_PREFERENCES, as: :radio_buttons, wrapper: :default, checked: (@volunteer.food_preferences.presence || :none)
|
||||||
= f.input :previous_experience
|
= f.input :previous_experience
|
||||||
= f.input :notes
|
= f.input :notes
|
||||||
|
= f.input :terms_accepted
|
||||||
.form-actions
|
.form-actions
|
||||||
= f.button :submit
|
= f.button :submit
|
||||||
|
|
|
@ -11,6 +11,7 @@ FactoryBot.define do
|
||||||
|
|
||||||
factory :administrator do
|
factory :administrator do
|
||||||
admin { true }
|
admin { true }
|
||||||
|
owner { true }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue