Last active
April 4, 2016 16:13
-
-
Save DmytroVasin/2ab7addcb686839802727c0b4f52f803 to your computer and use it in GitHub Desktop.
parts of code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
angular.module("Meek").controller "RadioStationsController", ( | |
$sce | |
$rootScope | |
$scope | |
$stateParams | |
Category | |
RadioStation | |
ApplicationService | |
RankService | |
) -> | |
$scope.category = Category.get({ id: $stateParams.categoryId }) | |
$scope.radioStation = RadioStation.get({ id: $stateParams.id }, (radioStation) -> | |
$rootScope.head.setMetaTag({ name: 'robots', content: 'noindex' }) if radioStation.noindex | |
$rootScope.head.setAllMetaInformation({ title: radioStation.meta_title, description: radioStation.meta_description, imagePath: radioStation.image, googlebotImage: radioStation.googlebot }) | |
RankService.initRankFor({ id: radioStation.id, type: 'RadioStation' }) | |
$scope.htmlSafeDescription = $sce.trustAsHtml(radioStation.description) | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
angular.module("Meek").service 'AuthenticationService', ( | |
$stateParams | |
$location | |
$state | |
$cookies | |
RadioStation | |
Auth | |
AlertService | |
FormService | |
ModalService | |
PlayerService | |
Layout | |
) -> | |
class Authentication | |
_newPasswordForm: $('#user-new-password-form') | |
constructor: -> | |
@setCurrentUser() | |
if $stateParams.reset_password_token | |
ModalService.newPassword($stateParams.reset_password_token) | |
return this | |
submitUserRegistration: (event) => | |
event.preventDefault() | |
_registrationForm = $(event.currentTarget) | |
FormService.clearErrors(_registrationForm) | |
credentials = { | |
email: _registrationForm.find('input[name=email]').val(), | |
password: _registrationForm.find('input[name=password]').val(), | |
password_confirmation: _registrationForm.find('input[name=password_confirmation]').val() | |
} | |
Auth.register(credentials).then ((user) => | |
# Auth#register automaticaly set _currentUser on save. | |
Auth._currentUser = undefined | |
ModalService.closeAll() | |
AlertService.display('You need confirm your email', 'warning') | |
return | |
), (errors) => | |
FormService.displayErrors(_registrationForm, errors.data) | |
return | |
return | |
submitLogin: (event) => | |
event.preventDefault() | |
_signInForm = $(event.currentTarget) | |
FormService.clearErrors(_signInForm) | |
credentials = { | |
email: _signInForm.find('input[name=email]').val(), | |
password: _signInForm.find('input[name=password]').val(), | |
} | |
Auth.login(credentials).then ((user) => | |
AlertService.display('Welcome back!', 'success') | |
@setCurrentUser() | |
ModalService.closeAll() | |
@redirectAfterLogin( user.slug ) if Layout.isMobile() | |
return | |
), (errors) => | |
FormService.displayErrors(_signInForm, errors.data) | |
return | |
return | |
isAuthenticated: -> | |
Auth.isAuthenticated() | |
setCurrentUser: => | |
Auth.currentUser().then ((user) => | |
@currentUser = user | |
@startDefaultRadio() | |
return | |
), (error) => | |
@currentUser = null | |
return | |
return | |
logout: => | |
Auth.logout().then ( => | |
@currentUser = undefined | |
AlertService.display('You have been logged out', 'success') | |
if PlayerService.isPlaying() && Layout.isMobile() | |
PlayerService.destroyPlayer() | |
$state.go('home') | |
), (error) -> | |
AlertService.display('There was a problem logging out. Please try again.', 'warning') | |
return | |
displayName: => | |
name = '' | |
if @currentUser? | |
name = @currentUser.full_name || @currentUser.email | |
return name | |
reloadCurrentUser: => | |
Auth.reset() | |
@setCurrentUser() | |
submitPasswordReset: (event) => | |
event.preventDefault() | |
_passwordResetForm = $(event.currentTarget) | |
FormService.clearErrors(_passwordResetForm) | |
result = FormService.submit(_passwordResetForm) | |
result.success (data) => | |
ModalService.closeAll() | |
AlertService.display('An email with password reset instructions has been sent to you.', 'success') | |
return | |
result.error (data) => | |
FormService.displayErrors(_passwordResetForm, data) | |
return | |
return | |
submitEmailReconfirm: (event) => | |
event.preventDefault() | |
_resendConfirmationForm = $(event.currentTarget) | |
FormService.clearErrors(_resendConfirmationForm) | |
result = FormService.submit(_resendConfirmationForm) | |
result.success (data) => | |
ModalService.closeAll() | |
AlertService.display('An email with confirmation link has been sent to you.', 'success') | |
return | |
result.error (data) => | |
FormService.displayErrors(_resendConfirmationForm, data) | |
return | |
return | |
submitNewPassword: (event) => | |
event.preventDefault() | |
_newPasswordForm = $(event.currentTarget) | |
FormService.clearErrors(_newPasswordForm) | |
result = FormService.submit(_newPasswordForm) | |
result.success (data) => | |
@reloadCurrentUser() | |
ModalService.closeAll() | |
AlertService.display('Your password has been reset.', 'success') | |
# $state.go('home') | |
$location.url('/') | |
return | |
result.error (data) => | |
FormService.displayErrors(_newPasswordForm, data) | |
return | |
return | |
changePassword: (event) => | |
event.preventDefault() | |
$form = $(event.target) | |
FormService.clearErrors($form) | |
$result = FormService.submit($form) | |
$result.success (data, status, headers, config) => | |
@reloadCurrentUser() | |
FormService.clearFields($form) | |
ModalService.closeAll() | |
AlertService.display('Your password was changed.', 'success') | |
$result.error (data, status, headers, config) => | |
FormService.displayErrors($form, data) | |
startDefaultRadio: => | |
return if !@currentUser.radio_station_id || !@currentUser.is_auto_play || PlayerService.isPlaying() | |
RadioStation.get({ id: @currentUser.radio_station_id }, (stationStation) -> | |
PlayerService.startRadio(stationStation) | |
) | |
return | |
redirectAfterLogin: (slug) => | |
url = $cookies.get('previouseState') | |
$location.url( url ) | |
return new Authentication() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
angular.module("Meek").service 'PlayerService', ( | |
$rootScope | |
$timeout | |
Metadata | |
AlertService | |
ModalService | |
Layout | |
Play | |
) -> | |
class Player | |
_meekPlayer: $('#meek-player') | |
_playerCardImg: $('.player-song-card img') | |
_playerCardDescriptionRow: $('.player-song-card .song-card-user-description-row') | |
_playerCardDescription: $('.player-song-card .song-card-user-description') | |
_playerCardTitle: $('.player-song-card .song-card-title') | |
constructor: -> | |
@_player = $("#player").jPlayer | |
swfPath: "../dist/jplayer" | |
solution: "html, flash" | |
supplied: "mp3" | |
preload: "auto" | |
volume: 0.8 | |
muted: false | |
backgroundColor: "#000000" | |
cssSelectorAncestor: "#meek-player" | |
cssSelector: | |
videoPlay: ".jp-video-play" | |
play: ".new-jp-play" | |
pause: ".new-jp-pause" | |
stop: ".new-jp-stop" | |
seekBar: ".new-jp-seek-bar" | |
playBar: ".new-jp-play-bar" | |
mute: ".new-jp-mute" | |
unmute: ".new-jp-unmute" | |
volumeBar: ".new-jp-volume-bar" | |
volumeBarValue: ".new-jp-volume-bar-value" | |
volumeMax: ".new-jp-volume-max" | |
playbackRateBar: ".jp-playback-rate-bar" | |
playbackRateBarValue: ".jp-playback-rate-bar-value" | |
currentTime: ".new-jp-current-time" | |
duration: ".new-jp-duration" | |
title: ".jp-title" | |
fullScreen: ".jp-full-screen" | |
restoreScreen: ".jp-restore-screen" | |
repeat: ".jp-repeat" | |
repeatOff: ".jp-repeat-off" | |
gui: ".jp-gui" | |
noSolution: ".jp-no-solution" | |
errorAlerts: false | |
warningAlerts: false | |
error: (e) -> | |
AlertService.display('The episode is not available at the moment.', 'warning') | |
return | |
return | |
startRadio: (radioStation) => | |
return if @_unAuthorized() | |
@_currentPodcast = undefined | |
@_currentEpisode = undefined | |
@_currentRadioStation = radioStation | |
@setStream(radioStation.name, radioStation.stream_url) | |
@showRadioStationPlayer() | |
@showRadioStationInfo() | |
@play() | |
return | |
showRadioStationInfo: => | |
$rootScope.playerInfo.setInfo( | |
type: 'radio' | |
image: @_currentRadioStation.image | |
title: @_currentRadioStation.name | |
favoriteId: @_currentRadioStation.id | |
favoriteType: 'RadioStation' | |
defaultRadioId: @_currentRadioStation.id | |
radioStationId: @_currentRadioStation.id | |
categoryId: @_currentRadioStation.category_id | |
currentPath: @_currentRadioStation.path | |
) | |
@_playerCardImg.attr('src', @_currentRadioStation.image) | |
@_playerCardTitle.html(@_currentRadioStation.name) | |
@_playerCardDescriptionRow.hide() | |
@loadRadioStationMetaData() | |
return | |
loadRadioStationMetaData: => | |
Metadata.get({ id: @_currentRadioStation.id }, (metadata) => | |
if metadata.artist? || metadata.song? | |
@_playerCardDescription.html("<span>Artist:</span>#{metadata.artist} | <span>Song:</span>#{metadata.song}") | |
@_playerCardDescriptionRow.show() | |
# since metadata was found, keep polling for changes. | |
@_radioMetadataTimeout = $timeout( @loadRadioStationMetaData, 5000 ) | |
else | |
@_playerCardDescriptionRow.hide() | |
) | |
return | |
startPodcast: (podcast, episode, stopped_at) => | |
return if @_unAuthorized() | |
@_currentPodcast = podcast | |
@_currentEpisode = episode | |
@_currentRadioStation = undefined | |
@setStream(@_currentEpisode.name, @_currentEpisode.stream_url) | |
@showPodcastPlayer() | |
@showPodcastInfo() | |
@play(stopped_at) | |
return | |
showPodcastInfo: => | |
$rootScope.playerInfo.setInfo( | |
type: 'podcast' | |
image: @_currentPodcast.image | |
title: @_currentPodcast.name | |
favoriteId: @_currentEpisode.id | |
favoriteType: 'Episode' | |
episodeId: @_currentEpisode.id | |
podcastId: @_currentPodcast.id | |
categoryId: @_currentPodcast.category_id | |
currentPath: @_currentEpisode.path | |
) | |
@_playerCardImg.attr('src', @_currentPodcast.image) | |
@_playerCardTitle.html(@_currentPodcast.name) | |
@_playerCardDescription.html(@_currentEpisode.name) | |
@_playerCardDescriptionRow.show() | |
return | |
setStream: (title, streamUrl) => | |
# cancel the metadata polling if active | |
$timeout.cancel(@_radioMetadataTimeout) if @_radioMetadataTimeout? | |
$timeout.cancel(@_playTrackingTimeout) if @_playTrackingTimeout? | |
if streamUrl | |
@_player.jPlayer('setMedia', { mp3: streamUrl }) | |
else | |
@_player.jPlayer('clearMedia') | |
return | |
play: (stopped_at) => | |
if stopped_at? | |
@_player.jPlayer('play', stopped_at) | |
else | |
@_player.jPlayer('play') | |
@showPlayer() | |
@startPlayTracking() | |
pause: => | |
@_player.jPlayer('pause') if @isPlaying() | |
showPlayer: => | |
$('body').addClass('player-enable') | |
@_meekPlayer.show() | |
showPodcastPlayer: => | |
@_meekPlayer.addClass('podcastIsPlaying') | |
@_meekPlayer.removeClass('radioStationIsPlaying') | |
showRadioStationPlayer: => | |
@_meekPlayer.addClass('radioStationIsPlaying') | |
@_meekPlayer.removeClass('podcastIsPlaying') | |
isPlaying: => | |
return @_currentPodcast || @_currentRadioStation | |
startPlayTracking: => | |
@playTrack = new Play() | |
if @_currentEpisode? | |
@playTrack.media_type = 'Episode' | |
@playTrack.media_id = @_currentEpisode.id | |
else | |
@playTrack.media_type = 'RadioStation' | |
@playTrack.media_id = @_currentRadioStation.id | |
@playTrack.$save() | |
@_playTrackingTimeout = $timeout( @playTracking, 3000 ) | |
return | |
playTracking: => | |
id = @playTrack.id | |
user_id = $rootScope.auth.currentUser.id if $rootScope.auth.isAuthenticated() | |
stopped_at = @_player.data("jPlayer").status.currentTime if @playTrack.media_type == 'Episode' | |
Play.update({ id: id, user_id: user_id, stopped_at: stopped_at }) unless @_player.data('jPlayer').status.paused | |
@_playTrackingTimeout = $timeout( @playTracking, 3000 ) | |
destroyPlayer: => | |
$timeout.cancel( @_playTrackingTimeout ) | |
$timeout.cancel( @_radioMetadataTimeout ) | |
@_currentPodcast = undefined | |
@_currentEpisode = undefined | |
@_currentRadioStation = undefined | |
$('body').removeClass('player-enable') | |
@_meekPlayer.hide() | |
@_player.jPlayer('stop') | |
_unAuthorized: => | |
if !$rootScope.auth.isAuthenticated() && Layout.isMobile() | |
ModalService.signInDialog() | |
return true | |
return false | |
return new Player() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Admins | |
class NetworkCompaniesController < ApplicationController | |
def index | |
self.resources = NetworkCompany.order('created_at DESC').page(params[:page]).per(10) | |
end | |
def show | |
find_resource | |
end | |
def new | |
self.resource = NetworkCompany.new | |
end | |
def create | |
self.resource = NetworkCompany.new(resource_params) | |
if resource.save | |
flash[:notice] = t('application.company_created') | |
redirect_to admins_network_companies_url | |
else | |
render :new | |
end | |
end | |
def edit | |
find_resource | |
end | |
def update | |
find_resource | |
if resource.update(resource_params) | |
flash[:notice] = t('application.company_updated') | |
redirect_to admins_network_company_url(id: params[:id]) | |
else | |
render :edit | |
end | |
end | |
def destroy | |
find_resource.destroy | |
flash[:notice] = t('application.company_destroy') | |
redirect_to admins_network_companies_url | |
end | |
private | |
def find_resource | |
self.resource = NetworkCompany.find(params[:id]) | |
end | |
def resource_params | |
params.require(:network_company).permit(:name, {company_ids: []}) | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class AccountsController < ::ApplicationController | |
skip_before_action :prepare_resource_controller | |
before_action :authenticate_user! | |
def edit | |
@account = current_user.account || current_user.build_account_with_default_params | |
end | |
def update | |
if current_user.update_attributes(get_params) | |
redirect_to root_path, notice: t('realtors.account.message_updated') | |
current_user.update(email: get_params[:account_attributes][:personal_email]) | |
else | |
@account = current_user.account | |
render :edit | |
end | |
end | |
def destroy | |
if current_user.provider || current_user.valid_password?(params[:user][:password]) | |
current_user.destroy | |
redirect_to root_url, notice: t('application.message_after_destroy') | |
else | |
redirect_to edit_account_path, alert: t('application.message_after_destroy_error') | |
end | |
end | |
# Not REST! | |
def inactive | |
current_user.account.update_attributes(active: false) | |
redirect_to root_path | |
end | |
private | |
def get_params | |
send("#{current_user.role}_params") | |
end | |
def tenant_params | |
params.require(:user).permit(:profile_image, | |
account_attributes: [:first_name, :last_name, :phone, | |
:personal_email ]) | |
end | |
def realtor_params | |
params.require(:user).permit(:profile_image, | |
account_attributes: [:first_name, :last_name, :phone, | |
:personal_email, :company_id, | |
:professional_email, :creci_number]) | |
end | |
def guest_params | |
params.require(:user).permit(:profile_image, | |
account_attributes: [:first_name, :last_name, :phone, | |
:personal_email, :company_id, :role, | |
:professional_email, :creci_number]) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class User < ActiveRecord::Base | |
attr_accessor :month, :day, :year | |
extend FriendlyId | |
include CustomerioCallbacks | |
friendly_id :username, use: :slugged | |
# Include default devise modules. Others available are: | |
# :validatable, :lockable, and :timeoutable | |
devise :database_authenticatable, :registerable, :recoverable, | |
:rememberable, :trackable, :omniauthable, :confirmable | |
belongs_to :church_type, class_name: 'ChurchType' | |
belongs_to :radio_station, class_name: 'RadioStation' | |
belongs_to :invitation | |
has_one :address, dependent: :destroy | |
has_one :identity, dependent: :destroy | |
has_many :sent_invitations, class_name: 'Invitation', foreign_key: 'sender_id', dependent: :destroy | |
has_many :audits, class_name: 'Audit', dependent: :destroy | |
has_many :favorites, class_name: 'Favorite', dependent: :destroy | |
has_many :plays, class_name: 'Play', dependent: :destroy | |
has_many :votes, dependent: :destroy | |
has_many :favorite_podcasts, through: :favorites, source: :favoritable, source_type: 'Podcast' | |
has_many :favorite_episodes, through: :favorites, source: :favoritable, source_type: 'Episode' | |
has_many :favorite_stations, through: :favorites, source: :favoritable, source_type: 'RadioStation' | |
accepts_nested_attributes_for :address | |
accepts_nested_attributes_for :audits | |
has_attached_file :background_pic | |
has_attached_file :profile_pic, default_url: ':default_user', styles: { normal: '200x200#' } | |
before_create :create_address | |
# Default Devise Validation ( devise module :validatable ) | |
# ------------------------ | |
validates_presence_of :email, if: :email_changed? | |
validates_uniqueness_of :email, allow_blank: true, if: :email_changed? | |
validates_format_of :email, with: Devise::email_regexp, allow_blank: true, if: :email_changed? | |
validates_presence_of :password, if: :password_required? | |
validates_confirmation_of :password, if: :password_required? | |
validates_length_of :password, within: Devise::password_length, allow_blank: true | |
def password_required? | |
!password.nil? || !password_confirmation.nil? | |
end | |
# ------------------------ | |
validates_length_of :language, maximum: 255, too_long: 'Pick a shorter name' | |
validates_length_of :church_name, maximum: 255, too_long: 'Pick a shorter name' | |
validates :username, uniqueness: true, allow_blank: true | |
validates :gender, inclusion: { in: ['Male', 'Female'] }, allow_blank: true | |
validates :christian_for, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 100 }, allow_blank: true | |
validate :format_username | |
validate :format_birth_date | |
validates_attachment_content_type :background_pic, content_type: /\Aimage\/.*\Z/ | |
validates_attachment_content_type :profile_pic, content_type: /\Aimage\/.*\Z/ | |
def full_name | |
"#{first_name} #{last_name}".strip.presence | |
end | |
def full_name_with_email | |
full_name || email | |
end | |
def update_tracked_fields(request) | |
super | |
audits.build(action: 'login', ip: last_sign_in_ip) if last_sign_in_at_changed? | |
end | |
# NOTE: This method is return additional values when we call | |
# | |
# respond_to current_user | |
def as_json(options = {}) | |
result = super | |
result['address'] = self.address | |
result['profile_pic'] = self.profile_pic.url(:normal) | |
result['background_pic'] = self.background_pic.url if self.background_pic.present? | |
result['full_name'] = self.full_name | |
result['church_type'] = self.church_type.try(:name) | |
result['year'] = self.birth_date.try(:year) | |
result['month'] = self.birth_date.try(:month) | |
result['day'] = self.birth_date.try(:day) | |
result['unconfirmed_email'] = self.unconfirmed_email | |
return result | |
end | |
def format_username | |
if self.username_changed? | |
precompiled_slug = self.username.downcase.parameterize | |
if User.where(slug: precompiled_slug).where.not(username: self.username).any? | |
errors.add( :username, 'Already has such slug') | |
end | |
end | |
end | |
def format_birth_date | |
if self.year && self.month && self.day | |
self.errors.add( :day, 'Date is invalid') unless convert_birth_date | |
end | |
end | |
def convert_birth_date | |
begin | |
civil_date = Date.civil( self.year.to_i, self.month.to_i, self.day.to_i ) | |
raise ArgumentError if civil_date > Date.today | |
self.birth_date = civil_date | |
rescue ArgumentError | |
false | |
end | |
end | |
def should_generate_new_friendly_id? | |
slug.blank? || username_changed? | |
end | |
# Note: We should remember user by default. | |
def remember_me | |
true | |
end | |
# Note: We should create address for new users | |
def create_address | |
build_address | |
end | |
def christian_for=(num) | |
num.gsub!(',', '.') if num.is_a?(String) | |
self[:christian_for] = num | |
end | |
end | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#main-header { | |
.right-side { | |
@include user-avatar(50) { | |
vertical-align: middle; | |
} | |
.header-search-link { display: none; } | |
.icon-wrapper { | |
line-height: initial; | |
display: inline-block; | |
vertical-align: middle; | |
} | |
.icon-search-header { | |
@include btn-search; | |
font-size: 25px; | |
line-height: $navbar-height; | |
z-index: 10; | |
} | |
.header-search { | |
position: relative; | |
input { | |
width: 100%; | |
padding: 0 60px 0 35px; | |
border: 0; | |
color: $header_grey; | |
line-height: $navbar-height; | |
background-color: transparent; | |
box-sizing: border-box; | |
vertical-align: top; | |
&:focus { box-shadow: none; } | |
} | |
.search-block { | |
width: 380px; | |
position: relative; | |
border-left: 1px solid #3b3b3b; | |
border-right: 1px solid #3b3b3b; | |
display: inline-block; | |
&> * { margin: 0px; } | |
} | |
} | |
.icon-login, .icon-invite { | |
padding-left: 7px; | |
font-size: 24px; | |
} | |
.icon-text { | |
font-family: $helvetica-neue, $open-bold; | |
font-size: 10px; | |
font-weight: bold; | |
} | |
} | |
} | |
@include tablet-landscape { | |
#main-header { | |
.right-side { | |
.header-search { | |
.search-block { width: 160px; } | |
} | |
} | |
} | |
} | |
@include tablet-portrait { | |
#main-header { | |
.right-side { | |
.header-search { | |
display: none; | |
input { | |
@include border-radius(5px); | |
line-height: 50px; | |
} | |
} | |
.header-search-link { | |
display: inline-block; | |
position: relative; | |
&.open { | |
&:after { | |
width: 0; | |
height: 0; | |
content: ''; | |
border-style: solid; | |
border-width: 0 7px 7px 7px; | |
border-color: transparent transparent rgba(0, 0, 0, 0.9) transparent; | |
position: absolute; | |
bottom: 0; | |
left: 40%; | |
} | |
.icon-search-header { display: none; } | |
.icon-close-bold { display: block; } | |
} | |
&.open + .header-search { | |
width: 100%; | |
display: block; | |
position: fixed; | |
left: 0; | |
background-color: rgba(0, 0, 0, 0.7); | |
line-height: 50px; | |
.search-block { | |
@include border-radius(5px); | |
width: 90%; | |
margin: 40px 0; | |
background-color: #fff; | |
.icon-search-header { line-height: 50px; } | |
} | |
} | |
.icon-search-header { | |
padding: 0; | |
display: block; | |
position: static; | |
} | |
.icon-close-bold { display: none; } | |
} | |
} | |
} | |
} | |
@include mobile-landscape { | |
#main-header { | |
.right-side { | |
.header-search { | |
input { padding: 0 50px 0 15px; } | |
} | |
.header-search-link { | |
&.open { | |
&:after { | |
bottom: 0; | |
left: 8px; | |
} | |
&+ .header-search { | |
.search-block { | |
.icon-search-header { padding: 0 14px 0 12px; } | |
} | |
} | |
} | |
.icon-search-header { | |
line-height: $header-mobile-height; | |
} | |
} | |
.icon-text { display: none; } | |
.user-avatar { | |
width: 30px; | |
height: 30px; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Shop::Cart < ActiveRecord::Base | |
belongs_to :buyer | |
belongs_to :order | |
has_many :cart_items | |
has_many :products, through: :cart_items | |
delegate :carrier, to: :buyer | |
def has_items? | |
cart_items.present? | |
end | |
def include_product? product | |
@ids ||= products.map &:id | |
@ids.include? product.id | |
end | |
def add_or_update_item item | |
cart_items << item | |
end | |
def remove_item_by_id id | |
item = cart_items.find id | |
item.destroy | |
end | |
def currency | |
# TODO: maybe to calculate currency by buyer.country even if the cart is empty? On client side we have done this. | |
return '' if cart_items.empty? | |
cart_items.first.product.pricing.currency | |
end | |
def total_quantity | |
cart_items.sum(:quantity) | |
end | |
def total_cost | |
cart_items.to_a.sum(&:total_price) | |
end | |
def duplicate_cart_items_into new_cart | |
new_cart.cart_items = self.cart_items.map do |ci| | |
new_ci = ci.dup | |
new_ci.ordered_product_id = nil | |
new_ci | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class User < ActiveRecord::Base | |
attr_accessor :month, :day, :year | |
extend FriendlyId | |
include CustomerioCallbacks | |
friendly_id :username, use: :slugged | |
# Include default devise modules. Others available are: | |
# :validatable, :lockable, and :timeoutable | |
devise :database_authenticatable, :registerable, :recoverable, | |
:rememberable, :trackable, :omniauthable, :confirmable | |
belongs_to :church_type, class_name: 'ChurchType' | |
belongs_to :radio_station, class_name: 'RadioStation' | |
belongs_to :invitation | |
has_one :address, dependent: :destroy | |
has_one :identity, dependent: :destroy | |
has_many :sent_invitations, class_name: 'Invitation', foreign_key: 'sender_id', dependent: :destroy | |
has_many :audits, class_name: 'Audit', dependent: :destroy | |
has_many :favorites, class_name: 'Favorite', dependent: :destroy | |
has_many :plays, class_name: 'Play', dependent: :destroy | |
has_many :votes, dependent: :destroy | |
has_many :favorite_podcasts, through: :favorites, source: :favoritable, source_type: 'Podcast' | |
has_many :favorite_episodes, through: :favorites, source: :favoritable, source_type: 'Episode' | |
has_many :favorite_stations, through: :favorites, source: :favoritable, source_type: 'RadioStation' | |
accepts_nested_attributes_for :address | |
accepts_nested_attributes_for :audits | |
has_attached_file :background_pic | |
has_attached_file :profile_pic, default_url: ':default_user', styles: { normal: '200x200#' } | |
before_create :create_address | |
# Default Devise Validation ( devise module :validatable ) | |
# ------------------------ | |
validates_presence_of :email, if: :email_changed? | |
validates_uniqueness_of :email, allow_blank: true, if: :email_changed? | |
validates_format_of :email, with: Devise::email_regexp, allow_blank: true, if: :email_changed? | |
validates_presence_of :password, if: :password_required? | |
validates_confirmation_of :password, if: :password_required? | |
validates_length_of :password, within: Devise::password_length, allow_blank: true | |
def password_required? | |
!password.nil? || !password_confirmation.nil? | |
end | |
# ------------------------ | |
validates_length_of :language, maximum: 255, too_long: 'Pick a shorter name' | |
validates_length_of :church_name, maximum: 255, too_long: 'Pick a shorter name' | |
validates :username, uniqueness: true, allow_blank: true | |
validates :gender, inclusion: { in: ['Male', 'Female'] }, allow_blank: true | |
validates :christian_for, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 100 }, allow_blank: true | |
validate :format_username | |
validate :format_birth_date | |
validates_attachment_content_type :background_pic, content_type: /\Aimage\/.*\Z/ | |
validates_attachment_content_type :profile_pic, content_type: /\Aimage\/.*\Z/ | |
def full_name | |
"#{first_name} #{last_name}".strip.presence | |
end | |
def full_name_with_email | |
full_name || email | |
end | |
def update_tracked_fields(request) | |
super | |
audits.build(action: 'login', ip: last_sign_in_ip) if last_sign_in_at_changed? | |
end | |
# NOTE: This method is return additional values when we call | |
# | |
# respond_to current_user | |
def as_json(options = {}) | |
result = super | |
result['address'] = self.address | |
result['profile_pic'] = self.profile_pic.url(:normal) | |
result['background_pic'] = self.background_pic.url if self.background_pic.present? | |
result['full_name'] = self.full_name | |
result['church_type'] = self.church_type.try(:name) | |
result['year'] = self.birth_date.try(:year) | |
result['month'] = self.birth_date.try(:month) | |
result['day'] = self.birth_date.try(:day) | |
result['unconfirmed_email'] = self.unconfirmed_email | |
return result | |
end | |
def format_username | |
if self.username_changed? | |
precompiled_slug = self.username.downcase.parameterize | |
if User.where(slug: precompiled_slug).where.not(username: self.username).any? | |
errors.add( :username, 'Already has such slug') | |
end | |
end | |
end | |
def format_birth_date | |
if self.year && self.month && self.day | |
self.errors.add( :day, 'Date is invalid') unless convert_birth_date | |
end | |
end | |
def convert_birth_date | |
begin | |
civil_date = Date.civil( self.year.to_i, self.month.to_i, self.day.to_i ) | |
raise ArgumentError if civil_date > Date.today | |
self.birth_date = civil_date | |
rescue ArgumentError | |
false | |
end | |
end | |
def should_generate_new_friendly_id? | |
slug.blank? || username_changed? | |
end | |
# Note: We should remember user by default. | |
def remember_me | |
true | |
end | |
# Note: We should create address for new users | |
def create_address | |
build_address | |
end | |
def christian_for=(num) | |
num.gsub!(',', '.') if num.is_a?(String) | |
self[:christian_for] = num | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
angular.module("Meek").service 'ShareService', ( | |
$location | |
) -> | |
class Share | |
rootUrls: -> | |
# Remvoe to UTILS | |
# window.location.origin | |
$location.$$protocol + '://' + $location.$$host | |
shareLink: ( type, opts ) => | |
url = @rootUrls() + opts.linkPath | |
image = @rootUrls() + opts.imagePath | |
text = opts.title | |
if type == 'google' | |
@_shareGoogle(url) | |
if type == 'facebook' | |
@_shareFacebook(url) | |
if type == 'twitter' | |
@_shareTwitter(url, text) | |
if type == 'pinterest' | |
@_sharePinterest(url, text, image) | |
return | |
_shareGoogle: (url) => | |
@_open("https://plus.google.com/share?url=#{ url }") | |
_shareFacebook: (url) => | |
@_open("https://www.facebook.com/sharer/sharer.php?u=#{ url }") | |
_shareTwitter: (url, text) => | |
@_open("https://twitter.com/share?url=#{ url }&text=#{ text }") | |
_sharePinterest: (url, text, image)=> | |
@_open("http://pinterest.com/pin/create/button/?url=#{ url }&description=#{ text }&media=#{ image }") | |
_open: (url) -> | |
window.open(url, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=300,width=600') | |
return | |
return new Share() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class SearchService | |
# Current service returns hash of Episodes/Podcasts/RadioStations that contains arrays of appropriate ids | |
# Appropriate ids depends from ts_rank | |
def initialize(search_phrase, page) | |
@options = base_options({ page: page }) | |
@phrase = sanitize_request( search_phrase ) | |
end | |
def call | |
return if @phrase.blank? | |
query = get_sql_raw_string(@phrase) | |
data = ActiveRecord::Base.connection.select_all(query) | |
prettify_datas(data) | |
end | |
private | |
def base_options(options) | |
options[:page] ||= 1 | |
options[:per_page] ||= 10 | |
options[:offset] = (options[:page].to_i - 1) * options[:per_page].to_i | |
options | |
end | |
def sanitize_request(search_phrase) | |
return nil if search_phrase.blank? | |
search_phrase.squish.gsub(/[^A-Za-z \-]/, '').split | |
end | |
# Method returns hash | |
# With Keys: "Episode", "Podcast", "RadioStation" values | |
# With Values: Array of proper Ids | |
def prettify_datas(data) | |
resulting_hash = {'Episode' => [], 'Podcast' => [], 'RadioStation' => []} | |
data.map{ |row| | |
{ | |
id: row['searchable_id'], | |
type: row['searchable_type'] | |
} | |
}.each { |subhash| resulting_hash[subhash[:type]] << subhash[:id] } | |
resulting_hash | |
end | |
def get_sql_raw_string(phrase) | |
query = prepare_phrase(phrase) | |
# http://www.postgresql.org/docs/9.1/static/textsearch-controls.html | |
<<-SQL | |
SELECT searchable_id, | |
searchable_type, | |
ts_rank(p_search.document, to_tsquery('english', '#{query}')) As rank | |
FROM ( | |
SELECT p.id AS searchable_id, | |
'Podcast' AS searchable_type, | |
setweight(to_tsvector('english', p.name), 'A') || | |
setweight(to_tsvector('english', p.h1), 'B') || | |
setweight(to_tsvector('english', p.short_description), 'C') AS document | |
FROM podcasts p | |
UNION | |
SELECT rs.id AS searchable_id, | |
'RadioStation' AS searchable_type, | |
setweight(to_tsvector('english', rs.name), 'A') || | |
setweight(to_tsvector('english', rs.h1), 'B') || | |
setweight(to_tsvector('english', rs.short_description), 'C') AS document | |
FROM radio_stations rs | |
UNION | |
SELECT ep.id AS searchable_id, | |
'Episode' AS searchable_type, | |
setweight(to_tsvector('english', ep.h1), 'A') AS document | |
FROM episodes ep | |
) p_search | |
WHERE p_search.document @@ to_tsquery('english', '#{query}') | |
ORDER BY ts_rank(p_search.document, to_tsquery('english', '#{query}')) DESC | |
LIMIT '#{ @options[:per_page] }' OFFSET '#{ @options[:offset] }'; | |
SQL | |
end | |
def prepare_phrase(phrase) | |
# http://www.postgresql.org/docs/9.1/static/datatype-textsearch.html | |
# This query will match any word in a tsvector that begins with "super". Note that prefixes are first processed by text search configurations, which means this comparison returns true: | |
# | |
# SELECT to_tsvector( 'postgraduate' ) @@ to_tsquery( 'postgres:*' ); | |
# ?column? | |
# ---------- | |
# t | |
# (1 row) | |
# | |
# because postgres gets stemmed to postgr: | |
phrase.map{|x| "#{x}:*"}.join(' & ') | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class LocationsService | |
attr_reader :row_types, :relation | |
def initialize | |
@row_types = %i[state city neighborhood].map{ |key| I18n.t(key, scope: self.class.name.underscore) } | |
@relation = City.unscoped.eager_load(:neighborhoods).order(:state_id, population: :desc) | |
end | |
# List for JS search element | |
# [['NameA <i>City</i>', '001'], ['NameB <i>City</i>', '002']] | |
def list_for_search | |
prev_state_id = nil | |
[].tap do |list| | |
relation.each do |city| | |
unless city.state_id == prev_state_id | |
prev_state_id = city.state_id | |
list << serch_list_row(city.state) | |
end | |
list << serch_list_row(city.state, city) | |
city.neighborhoods.each do |neighborhood| | |
list << serch_list_row(city.state, city, neighborhood) | |
end | |
end | |
end | |
end | |
# List of the cities per state_id for new|edit Property page City select | |
# {1=>[[2, "Rio Branco"], [1, "Cruzeiro do Sul"], [3, "Sena Madureira"], [4, "Tarauacá"]], | |
def cities_list | |
{}.tap do |list| | |
relation.each do |city| | |
(list[city.state_id] ||= []) << [city.id, city.name] | |
end | |
end | |
end | |
# List of the neighborhoods per city_id for new|edit Property page Neighborhood select | |
# {104=>["Tabapiry", "Arraial Dajuda", "Centro"] | |
def neighborhoods_list | |
{}.tap do |list| | |
relation.each do |city| | |
if city.neighborhoods.any? | |
list[city.id] = city.neighborhoods.map(&:name) | |
end | |
end | |
end | |
end | |
private | |
def serch_list_row(state, city = nil, neighborhood = nil) | |
ids = [state, city, neighborhood].compact.map(&:id) | |
names = [neighborhood.try(:name), city.try(:name), state.code].compact | |
["#{names.join(', ')} <i>#{self.row_types[ids.size - 1]}</i>", ids.join(',')] | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment