Speaker profile #2
3
Gemfile
3
Gemfile
|
@ -24,6 +24,9 @@ gem 'simple_form'
|
||||||
# Phone validation
|
# Phone validation
|
||||||
gem 'phony_rails'
|
gem 'phony_rails'
|
||||||
|
|
||||||
|
# Picture uploads
|
||||||
|
gem 'carrierwave'
|
||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
gem 'spring'
|
gem 'spring'
|
||||||
gem 'spring-commands-rspec'
|
gem 'spring-commands-rspec'
|
||||||
|
|
|
@ -36,6 +36,11 @@ GEM
|
||||||
rack (>= 1.0.0)
|
rack (>= 1.0.0)
|
||||||
rack-test (>= 0.5.4)
|
rack-test (>= 0.5.4)
|
||||||
xpath (~> 2.0)
|
xpath (~> 2.0)
|
||||||
|
carrierwave (0.10.0)
|
||||||
|
activemodel (>= 3.2.0)
|
||||||
|
activesupport (>= 3.2.0)
|
||||||
|
json (>= 1.7)
|
||||||
|
mime-types (>= 1.16)
|
||||||
celluloid (0.15.2)
|
celluloid (0.15.2)
|
||||||
timers (~> 1.1.0)
|
timers (~> 1.1.0)
|
||||||
choice (0.1.6)
|
choice (0.1.6)
|
||||||
|
@ -221,6 +226,7 @@ PLATFORMS
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
capybara
|
capybara
|
||||||
|
carrierwave
|
||||||
coffee-rails
|
coffee-rails
|
||||||
devise
|
devise
|
||||||
devise-i18n
|
devise-i18n
|
||||||
|
|
|
@ -13,3 +13,12 @@
|
||||||
*= require_tree .
|
*= require_tree .
|
||||||
*= require_self
|
*= require_self
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#main {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin: 0 0 1em 0;
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#flash_messages {
|
||||||
|
border: 1px solid #CCC;
|
||||||
|
background-color: #F1F1F1;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 0px 100px 10px 100px;
|
||||||
|
|
||||||
|
div {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notice {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
color: orange;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,30 +1,31 @@
|
||||||
#main {
|
.alert-error {
|
||||||
font-size: 16px;
|
color: red;
|
||||||
}
|
|
||||||
h1 {
|
|
||||||
margin: 0 0 1em 0;
|
|
||||||
font-size: 2em;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin: 0 0 1em 0;
|
margin: 0 0 1em 0;
|
||||||
border-top: 0.1em dotted #999;
|
border-top: 0.1em dotted #999;
|
||||||
padding: 1em 0;
|
padding: 1em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input label {
|
.input label {
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
display: block;
|
display: block;
|
||||||
width: 12em;
|
width: 12em;
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input input, .input textarea, .input select {
|
.input input, .input textarea, .input select {
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
width: 20em;
|
width: 20em;
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input textarea {
|
.input textarea {
|
||||||
height: 8em;
|
height: 8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input .hint, .input .error {
|
.input .hint, .input .error {
|
||||||
display: block;
|
display: block;
|
||||||
clear: both;
|
clear: both;
|
||||||
|
@ -34,11 +35,13 @@ h1 {
|
||||||
margin: 0 0 0 16em;
|
margin: 0 0 0 16em;
|
||||||
padding: 1em 0 0 0;
|
padding: 1em 0 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input .error {
|
.input .error {
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
padding: 1em 0 0 0;
|
padding: 1em 0 0 0;
|
||||||
color: #F00;
|
color: #F00;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input .error::before {
|
.input .error::before {
|
||||||
content: "⇧";
|
content: "⇧";
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -46,6 +49,7 @@ h1 {
|
||||||
margin: 0 0.2em 0 0;
|
margin: 0 0.2em 0 0;
|
||||||
transform: translate(0, 0.1em);
|
transform: translate(0, 0.1em);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 2em 0 0 13em;
|
margin: 2em 0 0 13em;
|
||||||
|
@ -63,9 +67,11 @@ h1 {
|
||||||
transition: background 200ms, border 200ms, transform 200ms;
|
transition: background 200ms, border 200ms, transform 200ms;
|
||||||
-webkit-transition: background 200ms, border 200ms, transform 200ms;
|
-webkit-transition: background 200ms, border 200ms, transform 200ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn:hover {
|
.btn:hover {
|
||||||
background: #152551;
|
background: #152551;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn:active {
|
.btn:active {
|
||||||
background: #597AD2;
|
background: #597AD2;
|
||||||
border-bottom: 0.2em solid #000;
|
border-bottom: 0.2em solid #000;
|
||||||
|
|
|
@ -2,4 +2,13 @@ class ApplicationController < ActionController::Base
|
||||||
# Prevent CSRF attacks by raising an exception.
|
# Prevent CSRF attacks by raising an exception.
|
||||||
# For APIs, you may want to use :null_session instead.
|
# For APIs, you may want to use :null_session instead.
|
||||||
protect_from_forgery with: :exception
|
protect_from_forgery with: :exception
|
||||||
|
before_filter :configure_permitted_parameters, if: :devise_controller?
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def configure_permitted_parameters
|
||||||
|
devise_parameter_sanitizer.for(:account_update) do |u|
|
||||||
|
u.permit(:email, :password, :password_confirmation, :current_password, speaker_profile_attributes: [:first_name, :last_name, :public_email, :organisation, :github, :twitter, :mobile_phone, :biography, :picture, :id])
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
class RegistrationsController < Devise::RegistrationsController
|
||||||
|
def edit
|
||||||
|
resource.build_speaker_profile unless resource.speaker_profile.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@user = User.find(current_user.id)
|
||||||
|
|
||||||
|
successfully_updated = if needs_password?(@user, params)
|
||||||
|
@user.update_with_password(devise_parameter_sanitizer.sanitize(:account_update))
|
||||||
|
else
|
||||||
|
# remove the virtual current_password attribute
|
||||||
|
# update_without_password doesn't know how to ignore it
|
||||||
|
params[:user].delete(:current_password)
|
||||||
|
@user.update_without_password(devise_parameter_sanitizer.sanitize(:account_update))
|
||||||
|
end
|
||||||
|
|
||||||
|
if successfully_updated
|
||||||
|
set_flash_message :notice, :updated
|
||||||
|
# Sign in the user bypassing validation in case their password changed
|
||||||
|
sign_in @user, :bypass => true
|
||||||
|
redirect_to after_update_path_for(@user)
|
||||||
|
else
|
||||||
|
render "edit"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def needs_password?(user, params)
|
||||||
|
user.email != params[:user][:email] ||
|
||||||
|
params[:user][:password].present? ||
|
||||||
|
params[:user][:password_confirmation].present?
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,9 @@
|
||||||
|
class SessionsController < Devise::SessionsController
|
||||||
|
def after_sign_in_path_for(user)
|
||||||
|
if user.speaker_profile.present?
|
||||||
|
stored_location_for(user) || signed_in_root_path(user)
|
||||||
|
else
|
||||||
|
edit_user_registration_path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,16 @@
|
||||||
|
class SpeakerProfilesController < ApplicationController
|
||||||
|
before_filter :authenticate_user!
|
||||||
|
before_action :assign_speaker_profile
|
||||||
|
|
||||||
|
def edit
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def assign_speaker_profile
|
||||||
|
@speaker_profile = SpeakerProfile.find_or_initialize_by(user: current_user)
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,7 +3,7 @@ class SpeakerProfile < ActiveRecord::Base
|
||||||
|
|
||||||
validates :first_name, presence: true
|
validates :first_name, presence: true
|
||||||
validates :last_name, presence: true
|
validates :last_name, presence: true
|
||||||
validates :photo_url, presence: true
|
validates :picture, presence: true
|
||||||
validates :mobile_phone, phony_plausible: true, presence: true
|
validates :mobile_phone, phony_plausible: true, presence: true
|
||||||
validates :biography, presence: true
|
validates :biography, presence: true
|
||||||
validates :public_email, format: {with: /\A[^@]+@[^@]+\z/}, allow_blank: true
|
validates :public_email, format: {with: /\A[^@]+@[^@]+\z/}, allow_blank: true
|
||||||
|
@ -12,6 +12,8 @@ class SpeakerProfile < ActiveRecord::Base
|
||||||
|
|
||||||
phony_normalize :mobile_phone, default_country_code: 'BG'
|
phony_normalize :mobile_phone, default_country_code: 'BG'
|
||||||
|
|
||||||
|
mount_uploader :picture, PictureUploader
|
||||||
|
|
||||||
def twitter=(handle)
|
def twitter=(handle)
|
||||||
write_attribute :twitter, handle.gsub(/\A@/,'') if handle
|
write_attribute :twitter, handle.gsub(/\A@/,'') if handle
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,4 +7,6 @@ class User < ActiveRecord::Base
|
||||||
has_one :speaker_profile
|
has_one :speaker_profile
|
||||||
has_many :lectures
|
has_many :lectures
|
||||||
has_many :workshops
|
has_many :workshops
|
||||||
|
|
||||||
|
accepts_nested_attributes_for :speaker_profile, update_only: true
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
class PictureUploader < CarrierWave::Uploader::Base
|
||||||
|
|
||||||
|
# Include RMagick or MiniMagick support:
|
||||||
|
# include CarrierWave::RMagick
|
||||||
|
# include CarrierWave::MiniMagick
|
||||||
|
|
||||||
|
# Choose what kind of storage to use for this uploader:
|
||||||
|
storage :file
|
||||||
|
# storage :fog
|
||||||
|
|
||||||
|
# Override the directory where uploaded files will be stored.
|
||||||
|
# This is a sensible default for uploaders that are meant to be mounted:
|
||||||
|
def store_dir
|
||||||
|
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Provide a default URL as a default if there hasn't been a file uploaded:
|
||||||
|
# def default_url
|
||||||
|
# # For Rails 3.1+ asset pipeline compatibility:
|
||||||
|
# # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
|
||||||
|
#
|
||||||
|
# "/images/fallback/" + [version_name, "default.png"].compact.join('_')
|
||||||
|
# end
|
||||||
|
|
||||||
|
# Process files as they are uploaded:
|
||||||
|
# process :scale => [200, 300]
|
||||||
|
#
|
||||||
|
# def scale(width, height)
|
||||||
|
# # do something
|
||||||
|
# end
|
||||||
|
|
||||||
|
# Create different versions of your uploaded files:
|
||||||
|
# version :thumb do
|
||||||
|
# process :resize_to_fit => [50, 50]
|
||||||
|
# end
|
||||||
|
|
||||||
|
# Add a white list of extensions which are allowed to be uploaded.
|
||||||
|
# For images you might use something like this:
|
||||||
|
# def extension_white_list
|
||||||
|
# %w(jpg jpeg gif png)
|
||||||
|
# end
|
||||||
|
|
||||||
|
# Override the filename of the uploaded files:
|
||||||
|
# Avoid using model.id or version_name here, see uploader/store.rb for details.
|
||||||
|
# def filename
|
||||||
|
# "something.jpg" if original_filename
|
||||||
|
# end
|
||||||
|
|
||||||
|
end
|
|
@ -1,16 +0,0 @@
|
||||||
<h2>Resend confirmation instructions</h2>
|
|
||||||
|
|
||||||
<%= simple_form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
|
|
||||||
<%= f.error_notification %>
|
|
||||||
<%= f.full_error :confirmation_token %>
|
|
||||||
|
|
||||||
<div class="form-inputs">
|
|
||||||
<%= f.input :email, required: true, autofocus: true %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-actions">
|
|
||||||
<%= f.button :submit, "Resend confirmation instructions" %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<%= render "devise/shared/links" %>
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
h2.entry-title Повторно изпращане на инструкции за потвърждаване на акаунт
|
||||||
|
|
||||||
|
= simple_form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f|
|
||||||
|
= f.error_notification
|
||||||
|
= f.full_error :confirmation_token
|
||||||
|
|
||||||
|
.form-inputs
|
||||||
|
= f.input :email, required: true, autofocus: true, hint: false
|
||||||
|
|
||||||
|
.form-actions
|
||||||
|
= f.button :submit, 'Изпрати отново инструкциите'
|
||||||
|
|
||||||
|
== render 'devise/shared/links'
|
|
@ -1,5 +1,5 @@
|
||||||
<p>Welcome <%= @email %>!</p>
|
<p>Добре дошли, <%= @email %>!</p>
|
||||||
|
|
||||||
<p>You can confirm your account email through the link below:</p>
|
<p>Можете да потвърдите акаунта си като кликнете на линка отдолу:</p>
|
||||||
|
|
||||||
<p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>
|
<p><%= link_to 'Потвърди акаунта ми', confirmation_url(@resource, confirmation_token: @token) %></p>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<p>Hello <%= @resource.email %>!</p>
|
<p>Здравейте, <%= @resource.email %>!</p>
|
||||||
|
|
||||||
<p>Someone has requested a link to change your password. You can do this through the link below.</p>
|
<p>Някой поиска линк за промяна на парола на аканута Ви. Паролата може да бъде променена от линкът отдолу.</p>
|
||||||
|
|
||||||
<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %></p>
|
<p><%= link_to 'Промяна на парола', edit_password_url(@resource, reset_password_token: @token) %></p>
|
||||||
|
|
||||||
<p>If you didn't request this, please ignore this email.</p>
|
<p>Ако не желаете да смените паролата си, моля изтрийте това писмо.</p>
|
||||||
<p>Your password won't change until you access the link above and create a new one.</p>
|
<p>Паролата Ви няма да бъде променена докато не кликнете горния линк и не въведете нова парола.</p>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<p>Hello <%= @resource.email %>!</p>
|
<p>Здравейте, <%= @resource.email %>!</p>
|
||||||
|
|
||||||
<p>Your account has been locked due to an excessive number of unsuccessful sign in attempts.</p>
|
<p>Акаунтът Ви беше заключен поради голям брой неуспешни опити за влизане в него.</p>
|
||||||
|
|
||||||
<p>Click the link below to unlock your account:</p>
|
<p>Кликнете линкът отдолу, за да го отключите:</p>
|
||||||
|
|
||||||
<p><%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %></p>
|
<p><%= link_to 'Отключване на акаунт', unlock_url(@resource, unlock_token: @token) %></p>
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
<h2>Change your password</h2>
|
|
||||||
|
|
||||||
<%= simple_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %>
|
|
||||||
<%= f.error_notification %>
|
|
||||||
|
|
||||||
<%= f.input :reset_password_token, as: :hidden %>
|
|
||||||
<%= f.full_error :reset_password_token %>
|
|
||||||
|
|
||||||
<div class="form-inputs">
|
|
||||||
<%= f.input :password, label: "New password", required: true, autofocus: true %>
|
|
||||||
<%= f.input :password_confirmation, label: "Confirm your new password", required: true %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-actions">
|
|
||||||
<%= f.button :submit, "Change my password" %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<%= render "devise/shared/links" %>
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
h2.entry-title Промяна на парола
|
||||||
|
|
||||||
|
= simple_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f|
|
||||||
|
= f.error_notification
|
||||||
|
|
||||||
|
= f.input :reset_password_token, as: :hidden
|
||||||
|
= f.full_error :reset_password_token
|
||||||
|
|
||||||
|
.form-inputs
|
||||||
|
= f.input :password, required: true, autofocus: true
|
||||||
|
= f.input :password_confirmation, required: true
|
||||||
|
|
||||||
|
.form-actions
|
||||||
|
= f.button :submit, 'Промяна на паролата'
|
||||||
|
|
||||||
|
= render 'devise/shared/links'
|
|
@ -1,15 +0,0 @@
|
||||||
<h2>Forgot your password?</h2>
|
|
||||||
|
|
||||||
<%= simple_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %>
|
|
||||||
<%= f.error_notification %>
|
|
||||||
|
|
||||||
<div class="form-inputs">
|
|
||||||
<%= f.input :email, required: true, autofocus: true %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-actions">
|
|
||||||
<%= f.button :submit, "Send me reset password instructions" %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<%= render "devise/shared/links" %>
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
h2.entry-title Забравена парола?
|
||||||
|
|
||||||
|
= simple_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f|
|
||||||
|
= f.error_notification
|
||||||
|
|
||||||
|
.form-inputs
|
||||||
|
= f.input :email, required: true, autofocus: true, hint: false
|
||||||
|
|
||||||
|
.form-actions
|
||||||
|
= f.button :submit, 'Изпрати ми инструкции за промяна на парола'
|
||||||
|
|
||||||
|
== render 'devise/shared/links'
|
|
@ -1,27 +0,0 @@
|
||||||
<h2>Edit <%= resource_name.to_s.humanize %></h2>
|
|
||||||
|
|
||||||
<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
|
|
||||||
<%= f.error_notification %>
|
|
||||||
|
|
||||||
<div class="form-inputs">
|
|
||||||
<%= f.input :email, required: true, autofocus: true %>
|
|
||||||
|
|
||||||
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
|
|
||||||
<p>Currently waiting confirmation for: <%= resource.unconfirmed_email %></p>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<%= f.input :password, autocomplete: "off", hint: "leave it blank if you don't want to change it", required: false %>
|
|
||||||
<%= f.input :password_confirmation, required: false %>
|
|
||||||
<%= f.input :current_password, hint: "we need your current password to confirm your changes", required: true %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-actions">
|
|
||||||
<%= f.button :submit, "Update" %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<h3>Cancel my account</h3>
|
|
||||||
|
|
||||||
<p>Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>
|
|
||||||
|
|
||||||
<%= link_to "Back", :back %>
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f|
|
||||||
|
.form_inputs
|
||||||
|
h2.entry-title Лекторски профил
|
||||||
|
= f.error_notification
|
||||||
|
= f.simple_fields_for :speaker_profile do |ff|
|
||||||
|
= ff.input :picture, as: :file
|
||||||
|
= ff.input :first_name
|
||||||
|
= ff.input :last_name
|
||||||
|
= ff.input :public_email
|
||||||
|
= ff.input :organisation
|
||||||
|
= ff.input :github
|
||||||
|
= ff.input :twitter
|
||||||
|
= ff.input :mobile_phone, input_html: {value: resource.speaker_profile.mobile_phone.try(:phony_formatted, format: :international)}
|
||||||
|
= ff.input :biography
|
||||||
|
|
||||||
|
.form-inputs
|
||||||
|
h3.entry-title Данни за вход в системата
|
||||||
|
= f.input :email, required: true, autofocus: true
|
||||||
|
|
||||||
|
- if devise_mapping.confirmable? && resource.pending_reconfirmation?
|
||||||
|
p
|
||||||
|
Очаква се потвърждение на: #{resource.unconfirmed_email}
|
||||||
|
|
||||||
|
= f.input :password, autocomplete: "off", hint: "Не попълвайте, ако не желаете да промените паролата си", required: false
|
||||||
|
= f.input :password_confirmation, required: false
|
||||||
|
= f.input :current_password, hint: "Попълнете, ако искате да промените паролата или имейл адреса си.", required: true
|
||||||
|
|
||||||
|
.form-actions
|
||||||
|
= f.button :submit, 'Обнови'
|
|
@ -1,17 +0,0 @@
|
||||||
<h2>Sign up</h2>
|
|
||||||
|
|
||||||
<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
|
|
||||||
<%= f.error_notification %>
|
|
||||||
|
|
||||||
<div class="form-inputs">
|
|
||||||
<%= f.input :email, required: true, autofocus: true %>
|
|
||||||
<%= f.input :password, required: true %>
|
|
||||||
<%= f.input :password_confirmation, required: true %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-actions">
|
|
||||||
<%= f.button :submit, "Sign up" %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<%= render "devise/shared/links" %>
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
h2.entry-title Регистрация
|
||||||
|
|
||||||
|
= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
|
||||||
|
= f.error_notification
|
||||||
|
|
||||||
|
.form-inputs
|
||||||
|
= f.input :email, required: true, autofocus: true
|
||||||
|
= f.input :password, required: true
|
||||||
|
= f.input :password_confirmation, required: true
|
||||||
|
|
||||||
|
.form-actions
|
||||||
|
= f.button :submit
|
||||||
|
|
||||||
|
== render 'devise/shared/links'
|
|
@ -1,15 +0,0 @@
|
||||||
<h2>Sign in</h2>
|
|
||||||
|
|
||||||
<%= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
|
|
||||||
<div class="form-inputs">
|
|
||||||
<%= f.input :email, required: false, autofocus: true %>
|
|
||||||
<%= f.input :password, required: false %>
|
|
||||||
<%= f.input :remember_me, as: :boolean if devise_mapping.rememberable? %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-actions">
|
|
||||||
<%= f.button :submit, "Sign in" %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<%= render "devise/shared/links" %>
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
h2.entry-title Вход
|
||||||
|
|
||||||
|
= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f|
|
||||||
|
.form-inputs
|
||||||
|
= f.input :email, required: false, autofocus: true, hint: false
|
||||||
|
= f.input :password, required: false, hint: false
|
||||||
|
= f.input :remember_me, as: :boolean if devise_mapping.rememberable?
|
||||||
|
|
||||||
|
.form-actions
|
||||||
|
= f.button :submit, 'Влез'
|
||||||
|
|
||||||
|
== render 'devise/shared/links'
|
|
@ -1,25 +0,0 @@
|
||||||
<%- if controller_name != 'sessions' %>
|
|
||||||
<%= link_to "Sign in", new_session_path(resource_name) %><br />
|
|
||||||
<% end -%>
|
|
||||||
|
|
||||||
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
|
|
||||||
<%= link_to "Sign up", new_registration_path(resource_name) %><br />
|
|
||||||
<% end -%>
|
|
||||||
|
|
||||||
<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
|
|
||||||
<%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
|
|
||||||
<% end -%>
|
|
||||||
|
|
||||||
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
|
|
||||||
<%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br />
|
|
||||||
<% end -%>
|
|
||||||
|
|
||||||
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
|
|
||||||
<%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
|
|
||||||
<% end -%>
|
|
||||||
|
|
||||||
<%- if devise_mapping.omniauthable? %>
|
|
||||||
<%- resource_class.omniauth_providers.each do |provider| %>
|
|
||||||
<%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider) %><br />
|
|
||||||
<% end -%>
|
|
||||||
<% end -%>
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
- if controller_name != 'sessions'
|
||||||
|
= link_to 'Вход', new_session_path(resource_name)
|
||||||
|
br
|
||||||
|
|
||||||
|
- if devise_mapping.registerable? && controller_name != 'registrations'
|
||||||
|
= link_to 'Регистрация', new_registration_path(resource_name)
|
||||||
|
br
|
||||||
|
|
||||||
|
- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations'
|
||||||
|
= link_to 'Забравена парола?', new_password_path(resource_name)
|
||||||
|
br
|
||||||
|
|
||||||
|
- if devise_mapping.confirmable? && controller_name != 'confirmations'
|
||||||
|
= link_to 'Не Сте получили инструкции за потвърждение?', new_confirmation_path(resource_name)
|
||||||
|
br
|
||||||
|
|
||||||
|
- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks'
|
||||||
|
= link_to 'Не Сте получили инструкции за отключване?', new_unlock_path(resource_name)
|
||||||
|
br
|
||||||
|
|
||||||
|
- if devise_mapping.omniauthable?
|
||||||
|
- resource_class.omniauth_providers.each do |provider|
|
||||||
|
= link_to 'Влез с #{provider.to_s.titleize}', omniauth_authorize_path(resource_name, provider)
|
|
@ -1,16 +0,0 @@
|
||||||
<h2>Resend unlock instructions</h2>
|
|
||||||
|
|
||||||
<%= simple_form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %>
|
|
||||||
<%= f.error_notification %>
|
|
||||||
<%= f.full_error :unlock_token %>
|
|
||||||
|
|
||||||
<div class="form-inputs">
|
|
||||||
<%= f.input :email, required: true, autofocus: true %>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-actions">
|
|
||||||
<%= f.button :submit, "Resend unlock instructions" %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<%= render "devise/shared/links" %>
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
h2 Изпрати отново инструкции за отключване
|
||||||
|
|
||||||
|
= simple_form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f|
|
||||||
|
= f.error_notification
|
||||||
|
= f.full_error :unlock_token
|
||||||
|
|
||||||
|
.form-inputs
|
||||||
|
= f.input :email, required: true, autofocus: true, hint: false
|
||||||
|
|
||||||
|
.form-actions
|
||||||
|
= f.button :submit, 'Изпрати отново инструкциите'
|
||||||
|
|
||||||
|
== render 'devise/shared/links'
|
|
@ -26,6 +26,7 @@
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div id="main">
|
<div id="main">
|
||||||
|
<%= render('/shared/flash_messages') unless flash.empty? %>
|
||||||
<%= yield %>
|
<%= yield %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
div#flash_messages
|
||||||
|
- flash.each do |key, value|
|
||||||
|
= content_tag :div, value, class: "flash #{key}"
|
|
@ -0,0 +1,3 @@
|
||||||
|
div#flash_messages
|
||||||
|
- flash.each do |key, value|
|
||||||
|
= content_tag :div, value, class: "flash #{key}"
|
|
@ -0,0 +1,14 @@
|
||||||
|
== simple_form_for @speaker_profile do |form|
|
||||||
|
p
|
||||||
|
= form.error_notification
|
||||||
|
|
||||||
|
.form-inputs
|
||||||
|
= form.input :first_name, autofocus: true
|
||||||
|
= form.input :last_name
|
||||||
|
= form.input :public_email
|
||||||
|
= form.input :organisation
|
||||||
|
= form.input :github
|
||||||
|
= form.input :twitter
|
||||||
|
= form.input :mobile_phone
|
||||||
|
= form.input :biography
|
||||||
|
= form.button :submit
|
|
@ -0,0 +1,3 @@
|
||||||
|
h1.entry-title Редакция на лекторски профил
|
||||||
|
|
||||||
|
== render 'form'
|
|
@ -22,6 +22,9 @@
|
||||||
bg:
|
bg:
|
||||||
activerecord:
|
activerecord:
|
||||||
models:
|
models:
|
||||||
|
user:
|
||||||
|
one: Потребител
|
||||||
|
other: Потребители
|
||||||
lecture:
|
lecture:
|
||||||
one: Лекция
|
one: Лекция
|
||||||
other: Лекции
|
other: Лекции
|
||||||
|
@ -30,6 +33,22 @@ bg:
|
||||||
other: Уъркшопи
|
other: Уъркшопи
|
||||||
track: Поток от лекции
|
track: Поток от лекции
|
||||||
attributes:
|
attributes:
|
||||||
|
user:
|
||||||
|
email: E-mail
|
||||||
|
current_password: Текуща парола
|
||||||
|
password: Парола
|
||||||
|
password_confirmation: Отново паролата
|
||||||
|
remember_me: Запомни ме
|
||||||
|
speaker_profile:
|
||||||
|
picture: Снимка
|
||||||
|
first_name: Име
|
||||||
|
last_name: Фамилия
|
||||||
|
organisation: Организация
|
||||||
|
public_email: Публичен email
|
||||||
|
mobile_phone: Мобилен телефон
|
||||||
|
biography: Биография
|
||||||
|
github: Github акаунт
|
||||||
|
twitter: Twitter акаунт
|
||||||
lecture:
|
lecture:
|
||||||
title: Заглавие
|
title: Заглавие
|
||||||
subtitle: Подзаглавие
|
subtitle: Подзаглавие
|
||||||
|
@ -48,6 +67,14 @@ bg:
|
||||||
description: Описание
|
description: Описание
|
||||||
notes: Забележки
|
notes: Забележки
|
||||||
track: Поток от лекции
|
track: Поток от лекции
|
||||||
|
errors:
|
||||||
|
models:
|
||||||
|
user:
|
||||||
|
attributes:
|
||||||
|
email:
|
||||||
|
invalid: не е валиден имейл адрес
|
||||||
|
password_confirmation:
|
||||||
|
confirmation: не съответства на паролата
|
||||||
errors:
|
errors:
|
||||||
messages:
|
messages:
|
||||||
improbable_phone: 'не е валиден телефонен номер'
|
improbable_phone: 'не е валиден телефонен номер'
|
|
@ -1,13 +1,27 @@
|
||||||
bg:
|
bg:
|
||||||
simple_form:
|
simple_form:
|
||||||
"yes": 'Да'
|
"yes": Да
|
||||||
"no": 'Не'
|
"no": Не
|
||||||
required:
|
required:
|
||||||
text: 'Задължително поле'
|
text: Задължително поле
|
||||||
mark: '*'
|
mark: '*'
|
||||||
error_notification:
|
error_notification:
|
||||||
default_message: "Моля разгледайте проблемите по-долу:"
|
default_message: 'Моля разгледайте посочените грешки във формуляра:'
|
||||||
hints:
|
hints:
|
||||||
|
user:
|
||||||
|
email: Имейл адресът Ви. Ще бъде видим само от организаторите.
|
||||||
|
password: Парола с дължина между 8 и 128 символа
|
||||||
|
password_confirmation: Отново въведената отгоре парола
|
||||||
|
speaker_profile:
|
||||||
|
picture: Ваша снимка
|
||||||
|
first_name: Малкото Ви име
|
||||||
|
last_name: Фамилното Ви име
|
||||||
|
organisation: Организацията, която представлявате
|
||||||
|
public_email: E-mail адрес, който ще бъде видим за посетителите
|
||||||
|
mobile_phone: Мобилен телефон, който ще бъде видим само за организаторите
|
||||||
|
biography: Опишете се с няколко изречения в трето лице :).
|
||||||
|
github: Github акаунтът Ви
|
||||||
|
twitter: Twitter акаунтът Ви
|
||||||
lecture:
|
lecture:
|
||||||
title: Заглавието на лекцията Ви
|
title: Заглавието на лекцията Ви
|
||||||
subtitle: Подзаглавието на лекцията Ви (ако има такова)
|
subtitle: Подзаглавието на лекцията Ви (ако има такова)
|
||||||
|
@ -25,4 +39,7 @@ bg:
|
||||||
language: Език, на който ще бъде воден уъркшопа
|
language: Език, на който ще бъде воден уъркшопа
|
||||||
abstract: Резюме на уъркшопа, което да може да бъде прочетено от посетителите
|
abstract: Резюме на уъркшопа, което да може да бъде прочетено от посетителите
|
||||||
description: Подробно описание на уъркшопа, което да бъде използвано от организаторския екип
|
description: Подробно описание на уъркшопа, което да бъде използвано от организаторския екип
|
||||||
notes: Забележки, които искате да споделите с организаторския екип
|
notes: Забележки, които искате да споделите с организаторския екип
|
||||||
|
labels:
|
||||||
|
user:
|
||||||
|
a: b
|
|
@ -2,7 +2,11 @@ Rails.application.routes.draw do
|
||||||
resources :lectures, only: [:index, :new, :create, :edit, :update, :show]
|
resources :lectures, only: [:index, :new, :create, :edit, :update, :show]
|
||||||
resources :workshops, only: [:index, :new, :create, :edit, :update, :show]
|
resources :workshops, only: [:index, :new, :create, :edit, :update, :show]
|
||||||
|
|
||||||
devise_for :users
|
devise_for :users, controllers: {registrations: 'registrations', sessions: 'sessions'}
|
||||||
|
|
||||||
|
resource :user, only: [] do
|
||||||
|
resource :speaker_profile, only: [:edit, :update]
|
||||||
|
end
|
||||||
|
|
||||||
root 'home#index'
|
root 'home#index'
|
||||||
# The priority is based upon order of creation: first created -> highest priority.
|
# The priority is based upon order of creation: first created -> highest priority.
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
class CreateSpeakerProfiles < ActiveRecord::Migration
|
class CreateSpeakerProfiles < ActiveRecord::Migration
|
||||||
def change
|
def change
|
||||||
create_table :speaker_profiles do |t|
|
create_table :speaker_profiles do |t|
|
||||||
t.string :first_name, null: false
|
t.string :first_name
|
||||||
t.string :last_name, null: false
|
t.string :last_name
|
||||||
t.string :organisation
|
t.string :organisation
|
||||||
t.string :public_email
|
t.string :public_email
|
||||||
t.string :photo_url, null: false
|
t.string :photo_url
|
||||||
t.string :mobile_phone, null: false
|
t.string :mobile_phone
|
||||||
t.text :biography, null: false
|
t.text :biography
|
||||||
t.string :github, null: false
|
t.string :github
|
||||||
t.string :twitter, null: false
|
t.string :twitter
|
||||||
|
|
||||||
t.timestamps
|
t.timestamps
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class RenamePictureUrlToPictureInSpeakerProfiles < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
rename_column :speaker_profiles, :photo_url, :picture
|
||||||
|
end
|
||||||
|
end
|
|
@ -6,7 +6,7 @@ FactoryGirl.define do
|
||||||
last_name "Doe"
|
last_name "Doe"
|
||||||
organisation "Example Org"
|
organisation "Example Org"
|
||||||
public_email "a@b.com"
|
public_email "a@b.com"
|
||||||
photo_url "http://placehold.it/50x50"
|
picture { Rack::Test::UploadedFile.new(File.join(Rails.root, 'spec', 'support', 'picture.jpg')) }
|
||||||
mobile_phone "0883444555"
|
mobile_phone "0883444555"
|
||||||
biography "Lorem ipsum"
|
biography "Lorem ipsum"
|
||||||
github "octocat"
|
github "octocat"
|
||||||
|
|
|
@ -9,8 +9,8 @@ RSpec.describe SpeakerProfile, :type => :model do
|
||||||
expect(build(:speaker_profile, last_name: nil)).to have_error_on :last_name
|
expect(build(:speaker_profile, last_name: nil)).to have_error_on :last_name
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'is invalid without a photo' do
|
it 'is invalid without a picture' do
|
||||||
expect(build(:speaker_profile, photo_url: nil)).to have_error_on :photo_url
|
expect(build(:speaker_profile, picture: nil)).to have_error_on :picture
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'mobile_phone' do
|
describe 'mobile_phone' do
|
||||||
|
|
Loading…
Reference in New Issue