Added excel sheet to housing page
This commit is contained in:
		
							parent
							
								
									2c976d40a4
								
							
						
					
					
						commit
						9356aa2d31
					
				
							
								
								
									
										5
									
								
								Gemfile
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								Gemfile
									
									
									
									
									
								
							| @ -42,16 +42,13 @@ gem 'geocoder' | |||||||
| gem 'paper_trail', '~> 3.0.5' | gem 'paper_trail', '~> 3.0.5' | ||||||
| gem 'sitemap_generator' | gem 'sitemap_generator' | ||||||
| gem 'activerecord-session_store' | gem 'activerecord-session_store' | ||||||
| # gem 'paypal-express', '0.7.1' |  | ||||||
| gem 'sass-json-vars' | gem 'sass-json-vars' | ||||||
| gem 'premailer-rails' | gem 'premailer-rails' | ||||||
| gem 'redcarpet' | gem 'redcarpet' | ||||||
| gem 'sidekiq' | gem 'sidekiq' | ||||||
| gem 'letter_opener' | gem 'letter_opener' | ||||||
| gem 'launchy' | gem 'launchy' | ||||||
| # gem 'axlsx' | gem 'to_spreadsheet', :git => 'git://github.com/glebm/to_spreadsheet.git' | ||||||
| # gem 'excelinator' |  | ||||||
| gem 'to_spreadsheet'#, :git => 'git://github.com/glebm/to_spreadsheet.git' |  | ||||||
| 
 | 
 | ||||||
| group :test do | group :test do | ||||||
| 	gem 'rspec' | 	gem 'rspec' | ||||||
|  | |||||||
| @ -92,84 +92,4 @@ | |||||||
| 			closeGuestSelector(); | 			closeGuestSelector(); | ||||||
| 		} | 		} | ||||||
| 	}); | 	}); | ||||||
| 	function closeOnTop() { |  | ||||||
| 		document.documentElement.removeAttribute('data-ontop'); |  | ||||||
| 		document.getElementById('guest_id').value = ''; |  | ||||||
| 		var target = document.querySelector('.on-top-target'); |  | ||||||
| 		target.removeAttribute('style'); |  | ||||||
| 		document.querySelector('body').removeAttribute('style'); |  | ||||||
| 		forEachElement('.on-top-control', function(control) { |  | ||||||
| 			control.classList.remove('on-top-control'); |  | ||||||
| 		}); |  | ||||||
| 	} |  | ||||||
| 	forEachElement('#guests .guest', function(guest) { |  | ||||||
| 		var button = guest.querySelector('.set-host'); |  | ||||||
| 		button.addEventListener('click', function(event) { |  | ||||||
| 			var target = document.querySelector('.on-top-target'); |  | ||||||
| 			var body = document.querySelector('body'); |  | ||||||
| 			// maintain our current height
 |  | ||||||
| 			body.setAttribute('style', 'height: ' + body.clientHeight + 'px'); |  | ||||||
| 			document.documentElement.setAttribute('data-ontop', 'set-host'); |  | ||||||
| 			guest.classList.add('on-top-control'); |  | ||||||
| 			target.setAttribute('style', 'bottom: ' + guest.clientHeight + 'px'); |  | ||||||
| 			document.getElementById('guest_id').value = guest.dataset.id; |  | ||||||
| 		}); |  | ||||||
| 	}); |  | ||||||
| 	forEachElement('#hosts .host', function(host) { |  | ||||||
| 		initHost(host); |  | ||||||
| 	}); |  | ||||||
| 
 |  | ||||||
| 	function initHost(host) { |  | ||||||
| 		forEachElement('.place-guest', function(button) { |  | ||||||
| 			button.addEventListener('click', function(event) { |  | ||||||
| 				var guest_id = document.getElementById('guest_id').value; |  | ||||||
| 				if (guest_id) { |  | ||||||
| 					var guest = document.getElementById('guest-' + guest_id); |  | ||||||
| 					var form = document.getElementById('hosts'); |  | ||||||
| 					var data = new FormData(form); |  | ||||||
| 
 |  | ||||||
| 					host.classList.add('requesting'); |  | ||||||
| 					if (guest.dataset.affectedHosts) { |  | ||||||
| 						data.append('affected-hosts', guest.dataset.affectedHosts); |  | ||||||
| 						forEach(guest.dataset.affectedHosts.split(','), function(host_id) { |  | ||||||
| 							h = document.getElementById('host-' + host_id); |  | ||||||
| 							if (h) { |  | ||||||
| 								h.classList.add('requesting'); |  | ||||||
| 							} |  | ||||||
| 						}); |  | ||||||
| 					} |  | ||||||
| 					data.append('button', button.value); |  | ||||||
| 
 |  | ||||||
| 					var request = new XMLHttpRequest(); |  | ||||||
| 					request.onreadystatechange = function() { |  | ||||||
| 						if (request.readyState == 4) { |  | ||||||
| 							if (request.status == 200) { |  | ||||||
| 								var response = JSON.parse(request.responseText); |  | ||||||
| 								for (var host_id in response.hosts) { |  | ||||||
| 									host_element = document.getElementById('host-' + host_id); |  | ||||||
| 									widget = response.hosts[host_id]; |  | ||||||
| 									host_element.className = widget.class; |  | ||||||
| 									host_element.querySelector('.guests').innerHTML = widget.html; |  | ||||||
| 									initHost(host_element); |  | ||||||
| 									host_element.classList.remove('requesting'); |  | ||||||
| 								} |  | ||||||
| 								for (var guest_id in response.affected_hosts) { |  | ||||||
| 									guest_element = document.getElementById('guest-' + guest_id); |  | ||||||
| 									if (guest_element) { |  | ||||||
| 										guest_element.setAttribute('data-affected-hosts', response.affected_hosts[guest_id].join(',')); |  | ||||||
| 									} |  | ||||||
| 								} |  | ||||||
| 							} |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 					request.open('POST', form.getAttribute('action'), true); |  | ||||||
| 					request.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); |  | ||||||
| 					request.send(data); |  | ||||||
| 				} |  | ||||||
| 			}); |  | ||||||
| 		}, host); |  | ||||||
| 	} |  | ||||||
| 	forEachElement('.on-top-close', function(button) { |  | ||||||
| 		button.addEventListener('click', closeOnTop); |  | ||||||
| 	}); |  | ||||||
| })(); | })(); | ||||||
|  | |||||||
| @ -288,7 +288,7 @@ class ConferencesController < ApplicationController | |||||||
| 				@organizations = Organization.all | 				@organizations = Organization.all | ||||||
| 
 | 
 | ||||||
| 				if request.format.xlsx? | 				if request.format.xlsx? | ||||||
| 					logger.info "Generating stats.xls" | 					logger.info "Generating organizations.xls" | ||||||
| 					@excel_data = { | 					@excel_data = { | ||||||
| 						columns: [:name, :street_address, :city, :subregion, :country, :postal_code, :email, :phone, :status], | 						columns: [:name, :street_address, :city, :subregion, :country, :postal_code, :email, :phone, :status], | ||||||
| 						keys: { | 						keys: { | ||||||
| @ -439,6 +439,80 @@ class ConferencesController < ApplicationController | |||||||
| 			when :housing | 			when :housing | ||||||
| 				# do a full analysis | 				# do a full analysis | ||||||
| 				analyze_housing | 				analyze_housing | ||||||
|  | 				 | ||||||
|  | 				if request.format.xlsx? | ||||||
|  | 					logger.info "Generating housing.xls" | ||||||
|  | 					@excel_data = { | ||||||
|  | 						columns: [:name, :phone, :street_address, :email, :availability, :considerations, :empty, :empty, :empty, :guests], | ||||||
|  | 						keys: { | ||||||
|  | 								name: 'forms.labels.generic.name', | ||||||
|  | 								street_address: 'forms.labels.generic.street_address', | ||||||
|  | 								email: 'forms.labels.generic.email', | ||||||
|  | 								phone: 'forms.labels.generic.phone', | ||||||
|  | 								availability: 'articles.conference_registration.headings.host.availability', | ||||||
|  | 								considerations: 'articles.conference_registration.headings.host.considerations' | ||||||
|  | 							}, | ||||||
|  | 						column_types: { | ||||||
|  | 								name: :bold, | ||||||
|  | 								guests: :table | ||||||
|  | 							}, | ||||||
|  | 						data: [], | ||||||
|  | 					} | ||||||
|  | 					@hosts.each do | id, host | | ||||||
|  | 						data = (host.housing_data || {}) | ||||||
|  | 						host_data = { | ||||||
|  | 							name: host.user.name, | ||||||
|  | 							street_address: data['address'], | ||||||
|  | 							email: host.user.email, | ||||||
|  | 							phone: data['phone'], | ||||||
|  | 							availability: data['availability'].present? && data['availability'][1].present? ? view_context.date_span(data['availability'][0].to_date, data['availability'][1].to_date) : '', | ||||||
|  | 							considerations: (data['considerations'].map { | consideration | view_context._"articles.conference_registration.host.considerations.#{consideration}" }).join(', '), | ||||||
|  | 							empty: '', | ||||||
|  | 							guests: { | ||||||
|  | 								columns: [:name, :area, :email, :arrival_departure, :allergies, :food, :companion, :city], | ||||||
|  | 								keys: { | ||||||
|  | 									name: 'forms.labels.generic.name', | ||||||
|  | 									area: 'articles.workshops.headings.space', | ||||||
|  | 									email: 'forms.labels.generic.email', | ||||||
|  | 									arrival_departure: 'articles.admin.housing.headings.arrival_departure', | ||||||
|  | 									companion: 'forms.labels.generic.companion', | ||||||
|  | 									city: 'forms.labels.generic.city', | ||||||
|  | 									food: 'forms.labels.generic.food', | ||||||
|  | 									allergies: 'forms.labels.generic.allergies' | ||||||
|  | 								}, | ||||||
|  | 								column_types: { | ||||||
|  | 									name: :bold | ||||||
|  | 								}, | ||||||
|  | 								data: [] | ||||||
|  | 							} | ||||||
|  | 						} | ||||||
|  | 
 | ||||||
|  | 						@housing_data[id][:guests].each do | space, space_data | | ||||||
|  | 							space_data.each do | guest_id, guest_data | | ||||||
|  | 								guest = guest_data[:guest] | ||||||
|  | 								if guest.present? | ||||||
|  | 									companion = view_context.companion(guest) | ||||||
|  | 
 | ||||||
|  | 									host_data[:guests][:data] << { | ||||||
|  | 										name: guest.user.name, | ||||||
|  | 										area: (view_context._"forms.labels.generic.#{space}"), | ||||||
|  | 										email: guest.user.email, | ||||||
|  | 										arrival_departure: guest.arrival.present? && guest.departure.present? ? view_context.date_span(guest.arrival.to_date, guest.departure.to_date) : '', | ||||||
|  | 										companion: companion.present? ? (companion.is_a?(User) ? companion.name : (view_context._"articles.conference_registration.terms.registration_status.#{companion}")) : '', | ||||||
|  | 										city: guest.city, | ||||||
|  | 										food: (view_context._"articles.conference_registration.questions.food.#{guest.food}"), | ||||||
|  | 										allergies: guest.allergies | ||||||
|  | 									} | ||||||
|  | 								end | ||||||
|  | 							end | ||||||
|  | 						end | ||||||
|  | 
 | ||||||
|  | 						@excel_data[:data] << host_data | ||||||
|  | 					end | ||||||
|  | 					return respond_to do | format | | ||||||
|  | 						format.xlsx { render xlsx: :stats, filename: "housing" } | ||||||
|  | 					end | ||||||
|  | 				end | ||||||
| 			when :locations | 			when :locations | ||||||
| 				@locations = EventLocation.where(:conference_id => @this_conference.id) | 				@locations = EventLocation.where(:conference_id => @this_conference.id) | ||||||
| 			when :events | 			when :events | ||||||
|  | |||||||
| @ -1529,6 +1529,122 @@ module ApplicationHelper | |||||||
| 		end | 		end | ||||||
| 	end | 	end | ||||||
| 
 | 
 | ||||||
|  | 	def excel_table(excel_data) | ||||||
|  | 		format_xls 'table' do | ||||||
|  | 			workbook use_autowidth: true | ||||||
|  | 			format bg_color: '333333' | ||||||
|  | 			format 'td', font_name: 'Calibri', fg_color: '333333' | ||||||
|  | 			format 'th', font_name: 'Calibri', b: true, bg_color: '333333', fg_color: 'ffffff' | ||||||
|  | 			format 'th.sub-table', font_name: 'Calibri', b: true, bg_color: 'DDDDDD', fg_color: '333333' | ||||||
|  | 			format 'td.datetime', num_fmt: 22, font_name: 'Courier New', sz: 10, fg_color: '333333' | ||||||
|  | 			format 'td.date.day', num_fmt: 14, font_name: 'Courier New', sz: 10, fg_color: '333333' | ||||||
|  | 			format 'td.money', num_fmt: 2, font_name: 'Courier New', sz: 10, fg_color: '333333' | ||||||
|  | 			format 'td.bold', font_name: 'Calibri', fg_color: '333333', b: true | ||||||
|  | 		end | ||||||
|  | 
 | ||||||
|  | 		key = excel_data[:key] || 'excel.columns' | ||||||
|  | 		 | ||||||
|  | 		content_tag(:table) do | ||||||
|  | 			(content_tag(:thead) do | ||||||
|  | 				content_tag(:tr, excel_header_columns(excel_data)) | ||||||
|  | 			end) + | ||||||
|  | 			content_tag(:tbody, excel_rows(excel_data)) | ||||||
|  | 		end | ||||||
|  | 	end | ||||||
|  | 
 | ||||||
|  | 	def excel_header_columns(data, padding = {}, class_name = nil) | ||||||
|  | 		columns = '' | ||||||
|  | 
 | ||||||
|  | 		data[:columns].each do |column| | ||||||
|  | 			unless data[:column_types].present? && data[:column_types][column] == :table | ||||||
|  | 				# columns += content_tag(:th, _(data[:keys][column].present? ? data[:keys][column] : "#{key}.#{column.to_s}"), class: class_name) | ||||||
|  | 				columns += content_tag(:th, data[:keys][column].present? ? _(data[:keys][column]) : '', class: class_name) | ||||||
|  | 			end | ||||||
|  | 		end | ||||||
|  | 
 | ||||||
|  | 		pad_columns(columns, padding, :th) | ||||||
|  | 	end | ||||||
|  | 
 | ||||||
|  | 	def excel_empty_row(data, padding = {}) | ||||||
|  | 		columns = '' | ||||||
|  | 
 | ||||||
|  | 		data[:columns].each do |column| | ||||||
|  | 			unless data[:column_types].present? && data[:column_types][column] == :table | ||||||
|  | 				columns += content_tag(:td) | ||||||
|  | 			end | ||||||
|  | 		end | ||||||
|  | 
 | ||||||
|  | 		content_tag(:tr, pad_columns(columns, padding)) | ||||||
|  | 	end | ||||||
|  | 
 | ||||||
|  | 	def pad_columns(columns, padding, column_type = :td) | ||||||
|  | 		left = '' | ||||||
|  | 
 | ||||||
|  | 		for i in 1..(padding['left'] || 0) | ||||||
|  | 			left += content_tag(:td) | ||||||
|  | 		end | ||||||
|  | 
 | ||||||
|  | 		right = '' | ||||||
|  | 		for i in 1..(padding['right'] || 0) | ||||||
|  | 			right += content_tag(:td) | ||||||
|  | 		end | ||||||
|  | 
 | ||||||
|  | 		(left + columns + right).html_safe | ||||||
|  | 	end | ||||||
|  | 
 | ||||||
|  | 	def excel_columns(row, data, padding = {}) | ||||||
|  | 		columns = '' | ||||||
|  | 
 | ||||||
|  | 		data[:columns].each do |column| | ||||||
|  | 			value = row[column].present? ? (_!row[column].to_s) : '' | ||||||
|  | 			class_name = nil | ||||||
|  | 			is_sub_table = false | ||||||
|  | 
 | ||||||
|  | 			if data[:column_types].present? && data[:column_types][column].present? | ||||||
|  | 				if data[:column_types][column] == :table | ||||||
|  | 					is_sub_table = true | ||||||
|  | 				else | ||||||
|  | 					class_name = data[:column_types][column] | ||||||
|  | 				end | ||||||
|  | 			end | ||||||
|  | 
 | ||||||
|  | 			columns += content_tag(:td, value, { class: class_name }) unless is_sub_table | ||||||
|  | 		end | ||||||
|  | 
 | ||||||
|  | 		pad_columns(columns, padding) | ||||||
|  | 	end | ||||||
|  | 
 | ||||||
|  | 	def excel_sub_tables(row, data, padding = {}) | ||||||
|  | 		rows = '' | ||||||
|  | 
 | ||||||
|  | 		# shift the table right | ||||||
|  | 		new_padding = { | ||||||
|  | 			'left' => (padding['right'] || 0) + 1, | ||||||
|  | 			'right' => (padding['right'] || 0) - 1 | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		data[:columns].each do |column| | ||||||
|  | 			if data[:column_types].present? && data[:column_types][column] == :table | ||||||
|  | 				puts row[column].to_json.to_s | ||||||
|  | 				rows += content_tag(:tr, excel_header_columns(row[column], new_padding, 'sub-table')) | ||||||
|  | 				rows += excel_rows(row[column], new_padding) | ||||||
|  | 				rows += excel_empty_row(row[column], new_padding) | ||||||
|  | 			end | ||||||
|  | 
 | ||||||
|  | 		end | ||||||
|  | 
 | ||||||
|  | 		rows.html_safe | ||||||
|  | 	end | ||||||
|  | 
 | ||||||
|  | 	def excel_rows(data, padding = {}) | ||||||
|  | 		rows = '' | ||||||
|  | 		data[:data].each do |row| | ||||||
|  | 			rows += content_tag(:tr, excel_columns(row, data, padding)) + | ||||||
|  | 				excel_sub_tables(row, data, padding) | ||||||
|  | 		end | ||||||
|  | 		rows.html_safe | ||||||
|  | 	end | ||||||
|  | 
 | ||||||
| 	private | 	private | ||||||
| 		def _original_content(value, lang) | 		def _original_content(value, lang) | ||||||
| 			content_tag(:div, ( | 			content_tag(:div, ( | ||||||
|  | |||||||
| @ -5,3 +5,6 @@ | |||||||
| 	= form_tag administration_update_path(@this_conference.slug, :housing), class: 'guest-dlg', id: 'guest-list-table' do | 	= form_tag administration_update_path(@this_conference.slug, :housing), class: 'guest-dlg', id: 'guest-list-table' do | ||||||
| 		%h3 Select a Guest | 		%h3 Select a Guest | ||||||
| 		#table | 		#table | ||||||
|  | .actions | ||||||
|  | 	= link_to (_'links.download.Excel'), administration_step_path(@this_conference.slug, :housing, :format => :xlsx), class: [:button, :download] | ||||||
|  | 
 | ||||||
|  | |||||||
| @ -4,15 +4,15 @@ | |||||||
| 	= data_set(:h4, 'articles.admin.stats.headings.incomplete_registrations') do | 	= data_set(:h4, 'articles.admin.stats.headings.incomplete_registrations') do | ||||||
| 		= ((@registration_count - @completed_registrations) || 0).to_s | 		= ((@registration_count - @completed_registrations) || 0).to_s | ||||||
| 	= data_set(:h4, 'articles.admin.stats.headings.bikes') do | 	= data_set(:h4, 'articles.admin.stats.headings.bikes') do | ||||||
| 		= (@completed_registrations || 0) > 0 ? "#{@bikes} (#{(@bikes / @completed_registrations.to_f).round(4) * 100.0}%)" : "0" | 		= (@completed_registrations || 0) > 0 ? "#{@bikes} (#{number_to_percentage(@bikes / @completed_registrations.to_f * 100.0)})" : "0" | ||||||
| 	= data_set(:h4, 'articles.admin.stats.headings.food.meat') do | 	= data_set(:h4, 'articles.admin.stats.headings.food.meat') do | ||||||
| 		= (@food[:all] || 0) > 0 ? "#{@food[:meat]} (#{(@food[:meat] / @food[:all].to_f).round(4) * 100.0}%)" : "0" | 		= (@food[:all] || 0) > 0 ? "#{@food[:meat]} (#{number_to_percentage(@food[:meat] / @food[:all].to_f * 100.0)})" : "0" | ||||||
| 	= data_set(:h4, 'articles.admin.stats.headings.food.vegetarian') do | 	= data_set(:h4, 'articles.admin.stats.headings.food.vegetarian') do | ||||||
| 		= (@food[:all] || 0) > 0 ? "#{@food[:vegetarian]} (#{(@food[:vegetarian] / @food[:all].to_f).round(4) * 100.0}%)" : "0" | 		= (@food[:all] || 0) > 0 ? "#{@food[:vegetarian]} (#{number_to_percentage(@food[:vegetarian] / @food[:all].to_f * 100.0)})" : "0" | ||||||
| 	= data_set(:h4, 'articles.admin.stats.headings.food.vegan') do | 	= data_set(:h4, 'articles.admin.stats.headings.food.vegan') do | ||||||
| 		= (@food[:all] || 0) > 0 ? "#{@food[:vegan]} (#{(@food[:vegan] / @food[:all].to_f).round(4) * 100.0}%)" : "0" | 		= (@food[:all] || 0) > 0 ? "#{@food[:vegan]} (#{number_to_percentage(@food[:vegan] / @food[:all].to_f * 100.0)})" : "0" | ||||||
| 	= data_set(:h4, 'articles.admin.stats.headings.donation_count') do | 	= data_set(:h4, 'articles.admin.stats.headings.donation_count') do | ||||||
| 		= (@completed_registrations || 0) > 0 ? "#{@donation_count} (#{(@donation_count / @completed_registrations.to_f).round(4) * 100.0}%)" : "0" | 		= (@completed_registrations || 0) > 0 ? "#{@donation_count} (#{number_to_percentage(@donation_count / @completed_registrations.to_f * 100.0)})" : "0" | ||||||
| 	= data_set(:h4, 'articles.admin.stats.headings.donation_total') do | 	= data_set(:h4, 'articles.admin.stats.headings.donation_total') do | ||||||
| 		= "$#{@donations || 0.00}" | 		= "$#{@donations || 0.00}" | ||||||
| .actions | .actions | ||||||
|  | |||||||
| @ -1,21 +1 @@ | |||||||
| - key = @excel_data[:key] || 'excel.columns' | = excel_table(@excel_data) | ||||||
| %table |  | ||||||
|   %thead |  | ||||||
|     %tr |  | ||||||
|       - @excel_data[:columns].each do |column| |  | ||||||
|         %th=_(@excel_data[:keys][column].present? ? @excel_data[:keys][column] : "#{key}.#{column.to_s}") |  | ||||||
|   %tbody |  | ||||||
|     - @excel_data[:data].each do |row| |  | ||||||
|       %tr |  | ||||||
|         - @excel_data[:columns].each do |column| |  | ||||||
|           %td{class: (@excel_data[:column_types].present? && @excel_data[:column_types][column].present?) ? @excel_data[:column_types][column] : nil}=(row[column].present? ? (_!row[column]) : '') |  | ||||||
| 
 |  | ||||||
| - format_xls 'table' do |  | ||||||
|   - workbook use_autowidth: true |  | ||||||
|   - format bg_color: '333333' |  | ||||||
|   - format 'td', font_name: 'Calibri', fg_color: '333333' |  | ||||||
|   - format 'th', font_name: 'Calibri', b: true, bg_color: '333333', fg_color: 'ffffff' |  | ||||||
|   - format 'td.datetime', num_fmt: 22, font_name: 'Courier New', sz: 10, fg_color: '333333' |  | ||||||
|   - format 'td.date.day', num_fmt: 14, font_name: 'Courier New', sz: 10, fg_color: '333333' |  | ||||||
|   - format 'td.money', num_fmt: 2, font_name: 'Courier New', sz: 10, fg_color: '333333' |  | ||||||
|   - format 'td.bold', font_name: 'Calibri', fg_color: '333333', b: true |  | ||||||
|  | |||||||
| @ -1264,7 +1264,7 @@ en: | |||||||
|         subregion: State / Province |         subregion: State / Province | ||||||
|         country: Country |         country: Country | ||||||
|         postal_code: Postal Code |         postal_code: Postal Code | ||||||
|         status: Status, |         status: Status | ||||||
|         bike: Bike |         bike: Bike | ||||||
|         food: Food |         food: Food | ||||||
|         housing: Housing |         housing: Housing | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user