Merge pull request #2415 from techAPJ/bulk-invite-users-5
FEATURE: Bulk Invite
This commit is contained in:
commit
0781531e3c
|
@ -14,6 +14,8 @@ export default Ember.ObjectController.extend({
|
||||||
this.set('searchTerm', '');
|
this.set('searchTerm', '');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
uploadText: function() { return I18n.t("user.invited.bulk_invite.text"); }.property(),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Observe the search term box with a debouncer and change the results.
|
Observe the search term box with a debouncer and change the results.
|
||||||
|
|
||||||
|
@ -42,6 +44,15 @@ export default Ember.ObjectController.extend({
|
||||||
return Discourse.User.currentProp('can_invite_to_forum');
|
return Discourse.User.currentProp('can_invite_to_forum');
|
||||||
}.property(),
|
}.property(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
Can the currently logged in user bulk invite users to the site (only Admin is allowed to perform this operation)
|
||||||
|
|
||||||
|
@property canBulkInvite
|
||||||
|
**/
|
||||||
|
canBulkInvite: function() {
|
||||||
|
return Discourse.User.currentProp('admin');
|
||||||
|
}.property(),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Should the search filter input box be displayed?
|
Should the search filter input box be displayed?
|
||||||
|
|
||||||
|
@ -75,5 +86,3 @@ export default Ember.ObjectController.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,14 @@ Discourse.UserInvitedRoute = Discourse.Route.extend({
|
||||||
showInvite: function() {
|
showInvite: function() {
|
||||||
Discourse.Route.showModal(this, 'invite', Discourse.User.current());
|
Discourse.Route.showModal(this, 'invite', Discourse.User.current());
|
||||||
this.controllerFor('invite').reset();
|
this.controllerFor('invite').reset();
|
||||||
|
},
|
||||||
|
|
||||||
|
uploadSuccess: function(filename) {
|
||||||
|
bootbox.alert(I18n.t("user.invited.bulk_invite.success", { filename: filename }));
|
||||||
|
},
|
||||||
|
|
||||||
|
uploadError: function(filename, message) {
|
||||||
|
bootbox.alert(I18n.t("user.invited.bulk_invite.error", { filename: filename, message: message }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,14 @@
|
||||||
|
|
||||||
<h2>{{i18n user.invited.title}}</h2>
|
<h2>{{i18n user.invited.title}}</h2>
|
||||||
|
|
||||||
{{#if canInviteToForum}}
|
<div class="pull-right">
|
||||||
<button {{action showInvite}} class='btn right'>{{i18n user.invited.create}}</button>
|
{{#if canInviteToForum}}
|
||||||
{{/if}}
|
<button {{action showInvite}} class='btn'>{{i18n user.invited.create}}</button>
|
||||||
|
{{/if}}
|
||||||
|
{{#if canBulkInvite}}
|
||||||
|
{{resumable-upload target="/invites/upload" success="uploadSuccess" error="uploadError" uploadText=uploadText}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
{{#if showSearch}}
|
{{#if showSearch}}
|
||||||
<form>
|
<form>
|
||||||
|
|
|
@ -2,7 +2,7 @@ require_dependency "backup_restore"
|
||||||
|
|
||||||
class Admin::BackupsController < Admin::AdminController
|
class Admin::BackupsController < Admin::AdminController
|
||||||
|
|
||||||
skip_before_filter :check_xhr, only: [:index, :show, :logs, :check_chunk, :upload_chunk]
|
skip_before_filter :check_xhr, only: [:index, :show, :logs, :check_backup_chunk, :upload_backup_chunk]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
|
@ -87,7 +87,7 @@ class Admin::BackupsController < Admin::AdminController
|
||||||
render nothing: true
|
render nothing: true
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_chunk
|
def check_backup_chunk
|
||||||
identifier = params.fetch(:resumableIdentifier)
|
identifier = params.fetch(:resumableIdentifier)
|
||||||
filename = params.fetch(:resumableFilename)
|
filename = params.fetch(:resumableFilename)
|
||||||
chunk_number = params.fetch(:resumableChunkNumber)
|
chunk_number = params.fetch(:resumableChunkNumber)
|
||||||
|
@ -95,15 +95,13 @@ class Admin::BackupsController < Admin::AdminController
|
||||||
|
|
||||||
# path to chunk file
|
# path to chunk file
|
||||||
chunk = Backup.chunk_path(identifier, filename, chunk_number)
|
chunk = Backup.chunk_path(identifier, filename, chunk_number)
|
||||||
# check whether the chunk has already been uploaded
|
# check chunk upload status
|
||||||
has_chunk_been_uploaded = File.exists?(chunk) && File.size(chunk) == current_chunk_size
|
status = HandleChunkUpload.check_chunk(chunk, current_chunk_size: current_chunk_size)
|
||||||
# 200 = exists, 404 = not uploaded yet
|
|
||||||
status = has_chunk_been_uploaded ? 200 : 404
|
|
||||||
|
|
||||||
render nothing: true, status: status
|
render nothing: true, status: status
|
||||||
end
|
end
|
||||||
|
|
||||||
def upload_chunk
|
def upload_backup_chunk
|
||||||
filename = params.fetch(:resumableFilename)
|
filename = params.fetch(:resumableFilename)
|
||||||
total_size = params.fetch(:resumableTotalSize).to_i
|
total_size = params.fetch(:resumableTotalSize).to_i
|
||||||
|
|
||||||
|
@ -118,15 +116,10 @@ class Admin::BackupsController < Admin::AdminController
|
||||||
|
|
||||||
# path to chunk file
|
# path to chunk file
|
||||||
chunk = Backup.chunk_path(identifier, filename, chunk_number)
|
chunk = Backup.chunk_path(identifier, filename, chunk_number)
|
||||||
dir = File.dirname(chunk)
|
# upload chunk
|
||||||
|
HandleChunkUpload.upload_chunk(chunk, file: file)
|
||||||
# ensure directory exists
|
|
||||||
FileUtils.mkdir_p(dir) unless Dir.exists?(dir)
|
|
||||||
# save chunk to the directory
|
|
||||||
File.open(chunk, "wb") { |f| f.write(file.tempfile.read) }
|
|
||||||
|
|
||||||
uploaded_file_size = chunk_number * chunk_size
|
uploaded_file_size = chunk_number * chunk_size
|
||||||
|
|
||||||
# when all chunks are uploaded
|
# when all chunks are uploaded
|
||||||
if uploaded_file_size + current_chunk_size >= total_size
|
if uploaded_file_size + current_chunk_size >= total_size
|
||||||
# merge all the chunks in a background thread
|
# merge all the chunks in a background thread
|
||||||
|
|
|
@ -3,7 +3,7 @@ class InvitesController < ApplicationController
|
||||||
skip_before_filter :check_xhr
|
skip_before_filter :check_xhr
|
||||||
skip_before_filter :redirect_to_login_if_required
|
skip_before_filter :redirect_to_login_if_required
|
||||||
|
|
||||||
before_filter :ensure_logged_in, only: [:destroy, :create]
|
before_filter :ensure_logged_in, only: [:destroy, :create, :check_csv_chunk, :upload_csv_chunk]
|
||||||
|
|
||||||
def show
|
def show
|
||||||
invite = Invite.find_by(invite_key: params[:id])
|
invite = Invite.find_by(invite_key: params[:id])
|
||||||
|
@ -51,4 +51,48 @@ class InvitesController < ApplicationController
|
||||||
render nothing: true
|
render nothing: true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def check_csv_chunk
|
||||||
|
guardian.ensure_can_bulk_invite_to_forum!(current_user)
|
||||||
|
|
||||||
|
filename = params.fetch(:resumableFilename)
|
||||||
|
identifier = params.fetch(:resumableIdentifier)
|
||||||
|
chunk_number = params.fetch(:resumableChunkNumber)
|
||||||
|
current_chunk_size = params.fetch(:resumableCurrentChunkSize).to_i
|
||||||
|
|
||||||
|
# path to chunk file
|
||||||
|
chunk = Invite.chunk_path(identifier, filename, chunk_number)
|
||||||
|
# check chunk upload status
|
||||||
|
status = HandleChunkUpload.check_chunk(chunk, current_chunk_size: current_chunk_size)
|
||||||
|
|
||||||
|
render nothing: true, status: status
|
||||||
|
end
|
||||||
|
|
||||||
|
def upload_csv_chunk
|
||||||
|
guardian.ensure_can_bulk_invite_to_forum!(current_user)
|
||||||
|
|
||||||
|
filename = params.fetch(:resumableFilename)
|
||||||
|
return render status: 415, text: I18n.t("bulk_invite.file_should_be_csv") unless filename.to_s.end_with?(".csv")
|
||||||
|
|
||||||
|
file = params.fetch(:file)
|
||||||
|
identifier = params.fetch(:resumableIdentifier)
|
||||||
|
chunk_number = params.fetch(:resumableChunkNumber).to_i
|
||||||
|
chunk_size = params.fetch(:resumableChunkSize).to_i
|
||||||
|
total_size = params.fetch(:resumableTotalSize).to_i
|
||||||
|
current_chunk_size = params.fetch(:resumableCurrentChunkSize).to_i
|
||||||
|
|
||||||
|
# path to chunk file
|
||||||
|
chunk = Invite.chunk_path(identifier, filename, chunk_number)
|
||||||
|
# upload chunk
|
||||||
|
HandleChunkUpload.upload_chunk(chunk, file: file)
|
||||||
|
|
||||||
|
uploaded_file_size = chunk_number * chunk_size
|
||||||
|
# when all chunks are uploaded
|
||||||
|
if uploaded_file_size + current_chunk_size >= total_size
|
||||||
|
# handle bulk_invite processing in a background thread
|
||||||
|
Jobs.enqueue(:bulk_invite, filename: filename, identifier: identifier, chunks: chunk_number, current_user_id: current_user.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
render nothing: true
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,27 +14,11 @@ module Jobs
|
||||||
|
|
||||||
backup_path = "#{Backup.base_directory}/#{filename}"
|
backup_path = "#{Backup.base_directory}/#{filename}"
|
||||||
tmp_backup_path = "#{backup_path}.tmp"
|
tmp_backup_path = "#{backup_path}.tmp"
|
||||||
|
# path to tmp directory
|
||||||
# delete destination files
|
|
||||||
File.delete(backup_path) rescue nil
|
|
||||||
File.delete(tmp_backup_path) rescue nil
|
|
||||||
|
|
||||||
# merge all the chunks
|
|
||||||
File.open(tmp_backup_path, "a") do |backup|
|
|
||||||
(1..chunks).each do |chunk_number|
|
|
||||||
# path to chunk
|
|
||||||
chunk_path = Backup.chunk_path(identifier, filename, chunk_number)
|
|
||||||
# add chunk to backup
|
|
||||||
backup << File.open(chunk_path).read
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# rename tmp backup to final backup name
|
|
||||||
FileUtils.mv(tmp_backup_path, backup_path, force: true)
|
|
||||||
|
|
||||||
# remove tmp directory
|
|
||||||
tmp_directory = File.dirname(Backup.chunk_path(identifier, filename, 0))
|
tmp_directory = File.dirname(Backup.chunk_path(identifier, filename, 0))
|
||||||
FileUtils.rm_rf(tmp_directory) rescue nil
|
|
||||||
|
# merge all chunks
|
||||||
|
HandleChunkUpload.merge_chunks(chunks, upload_path: backup_path, tmp_upload_path: tmp_backup_path, model: Backup, identifier: identifier, filename: filename, tmp_directory: tmp_directory)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
require 'csv'
|
||||||
|
require_dependency 'system_message'
|
||||||
|
|
||||||
|
module Jobs
|
||||||
|
|
||||||
|
class BulkInvite < Jobs::Base
|
||||||
|
sidekiq_options retry: false
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@logs = []
|
||||||
|
@sent = 0
|
||||||
|
@failed = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute(args)
|
||||||
|
filename = args[:filename]
|
||||||
|
identifier = args[:identifier]
|
||||||
|
chunks = args[:chunks].to_i
|
||||||
|
current_user = User.find_by(id: args[:current_user_id])
|
||||||
|
|
||||||
|
raise Discourse::InvalidParameters.new(:filename) if filename.blank?
|
||||||
|
raise Discourse::InvalidParameters.new(:identifier) if identifier.blank?
|
||||||
|
raise Discourse::InvalidParameters.new(:chunks) if chunks <= 0
|
||||||
|
|
||||||
|
csv_path = "#{Invite.base_directory}/#{filename}"
|
||||||
|
tmp_csv_path = "#{csv_path}.tmp"
|
||||||
|
# path to tmp directory
|
||||||
|
tmp_directory = File.dirname(Invite.chunk_path(identifier, filename, 0))
|
||||||
|
|
||||||
|
# merge all chunks
|
||||||
|
HandleChunkUpload.merge_chunks(chunks, upload_path: csv_path, tmp_upload_path: tmp_csv_path, model: Invite, identifier: identifier, filename: filename, tmp_directory: tmp_directory)
|
||||||
|
|
||||||
|
# read csv file, and send out invitations
|
||||||
|
CSV.foreach(csv_path) do |csv_info|
|
||||||
|
if !csv_info[0].nil?
|
||||||
|
if validate_email(csv_info[0])
|
||||||
|
Invite.invite_by_email(csv_info[0], current_user, topic=nil)
|
||||||
|
@sent += 1
|
||||||
|
else
|
||||||
|
log "Invalid email '#{csv_info[0]}' at line number '#{$INPUT_LINE_NUMBER}'"
|
||||||
|
@failed += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# send notification to user regarding progress
|
||||||
|
notify_user(current_user)
|
||||||
|
|
||||||
|
# since emails have already been sent out, delete the uploaded csv file
|
||||||
|
FileUtils.rm_rf(csv_path) rescue nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_email(email)
|
||||||
|
/\A[^@\s]+@([^@\s]+\.)+[^@\s]+\z/.match(email)
|
||||||
|
end
|
||||||
|
|
||||||
|
def log(message)
|
||||||
|
puts(message) rescue nil
|
||||||
|
save_log(message)
|
||||||
|
end
|
||||||
|
|
||||||
|
def save_log(message)
|
||||||
|
@logs << "[#{Time.now}] #{message}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def notify_user(current_user)
|
||||||
|
if current_user
|
||||||
|
if (@sent > 0 && @failed == 0)
|
||||||
|
SystemMessage.create(current_user, :bulk_invite_succeeded, sent: @sent)
|
||||||
|
else
|
||||||
|
SystemMessage.create(current_user, :bulk_invite_failed, sent: @sent, failed: @failed, logs: @logs.join("\n"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -129,6 +129,14 @@ class Invite < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
i
|
i
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.base_directory
|
||||||
|
File.join(Rails.root, "public", "csv", RailsMultisite::ConnectionManagement.current_db)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.chunk_path(identifier, filename, chunk_number)
|
||||||
|
File.join(Invite.base_directory, "tmp", identifier, "#{filename}.part#{chunk_number}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
class HandleChunkUpload
|
||||||
|
|
||||||
|
def initialize(chunk, params={})
|
||||||
|
@chunk = chunk
|
||||||
|
@params = params
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.check_chunk(chunk, params)
|
||||||
|
HandleChunkUpload.new(chunk, params).check_chunk
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.upload_chunk(chunk, params)
|
||||||
|
HandleChunkUpload.new(chunk, params).upload_chunk
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.merge_chunks(chunk, params)
|
||||||
|
HandleChunkUpload.new(chunk, params).merge_chunks
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_chunk
|
||||||
|
# check whether the chunk has already been uploaded
|
||||||
|
has_chunk_been_uploaded = File.exists?(@chunk) && File.size(@chunk) == @params[:current_chunk_size]
|
||||||
|
# 200 = exists, 404 = not uploaded yet
|
||||||
|
status = has_chunk_been_uploaded ? 200 : 404
|
||||||
|
end
|
||||||
|
|
||||||
|
def upload_chunk
|
||||||
|
# path to chunk file
|
||||||
|
dir = File.dirname(@chunk)
|
||||||
|
# ensure directory exists
|
||||||
|
FileUtils.mkdir_p(dir) unless Dir.exists?(dir)
|
||||||
|
# save chunk to the directory
|
||||||
|
File.open(@chunk, "wb") { |f| f.write(@params[:file].tempfile.read) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def merge_chunks
|
||||||
|
upload_path = @params[:upload_path]
|
||||||
|
tmp_upload_path = @params[:tmp_upload_path]
|
||||||
|
model = @params[:model]
|
||||||
|
identifier = @params[:identifier]
|
||||||
|
filename = @params[:filename]
|
||||||
|
tmp_directory = @params[:tmp_directory]
|
||||||
|
|
||||||
|
# delete destination files
|
||||||
|
File.delete(upload_path) rescue nil
|
||||||
|
File.delete(tmp_upload_path) rescue nil
|
||||||
|
|
||||||
|
# merge all the chunks
|
||||||
|
File.open(tmp_upload_path, "a") do |file|
|
||||||
|
(1..@chunk).each do |chunk_number|
|
||||||
|
# path to chunk
|
||||||
|
chunk_path = model.chunk_path(identifier, filename, chunk_number)
|
||||||
|
# add chunk to file
|
||||||
|
file << File.open(chunk_path).read
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# rename tmp file to final file name
|
||||||
|
FileUtils.mv(tmp_upload_path, upload_path, force: true)
|
||||||
|
|
||||||
|
# remove tmp directory
|
||||||
|
FileUtils.rm_rf(tmp_directory) rescue nil
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -414,6 +414,11 @@ en:
|
||||||
days_visited: "Days Visited"
|
days_visited: "Days Visited"
|
||||||
account_age_days: "Account age in days"
|
account_age_days: "Account age in days"
|
||||||
create: "Send an Invite"
|
create: "Send an Invite"
|
||||||
|
bulk_invite:
|
||||||
|
text: "Batch Invite from File"
|
||||||
|
uploading: "UPLOADING"
|
||||||
|
success: "File has been uploaded successfully, you will be notified shortly with progress."
|
||||||
|
error: "There has been an error while uploading '{{filename}}': {{message}}"
|
||||||
|
|
||||||
password:
|
password:
|
||||||
title: "Password"
|
title: "Password"
|
||||||
|
|
|
@ -39,6 +39,9 @@ en:
|
||||||
embed:
|
embed:
|
||||||
load_from_remote: "There was an error loading that post."
|
load_from_remote: "There was an error loading that post."
|
||||||
|
|
||||||
|
bulk_invite:
|
||||||
|
file_should_be_csv: "The uploaded file should be of csv format."
|
||||||
|
|
||||||
backup:
|
backup:
|
||||||
operation_already_running: "An operation is currently running. Can't start a new job right now."
|
operation_already_running: "An operation is currently running. Can't start a new job right now."
|
||||||
backup_file_should_be_tar_gz: "The backup file should be a .tar.gz archive."
|
backup_file_should_be_tar_gz: "The backup file should be a .tar.gz archive."
|
||||||
|
@ -1251,6 +1254,21 @@ en:
|
||||||
%{logs}
|
%{logs}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
bulk_invite_succeeded:
|
||||||
|
subject_template: "Bulk Invite processed successfully!"
|
||||||
|
text_body_template: "The bulk invite has been processed, %{sent} invites sent."
|
||||||
|
|
||||||
|
bulk_invite_failed:
|
||||||
|
subject_template: "Bulk Invite processed with some errors!"
|
||||||
|
text_body_template: |
|
||||||
|
The bulk invite has been processed, %{sent} invites sent and %{failed} invites failed.
|
||||||
|
|
||||||
|
Here's the log:
|
||||||
|
|
||||||
|
```
|
||||||
|
%{logs}
|
||||||
|
```
|
||||||
|
|
||||||
email_error_notification:
|
email_error_notification:
|
||||||
subject_template: "Error parsing email"
|
subject_template: "Error parsing email"
|
||||||
text_body_template: |
|
text_body_template: |
|
||||||
|
|
|
@ -133,8 +133,8 @@ Discourse::Application.routes.draw do
|
||||||
get "cancel" => "backups#cancel"
|
get "cancel" => "backups#cancel"
|
||||||
get "rollback" => "backups#rollback"
|
get "rollback" => "backups#rollback"
|
||||||
put "readonly" => "backups#readonly"
|
put "readonly" => "backups#readonly"
|
||||||
get "upload" => "backups#check_chunk"
|
get "upload" => "backups#check_backup_chunk"
|
||||||
post "upload" => "backups#upload_chunk"
|
post "upload" => "backups#upload_backup_chunk"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -361,7 +361,12 @@ Discourse::Application.routes.draw do
|
||||||
get "/posts/:id/expand-embed" => "posts#expand_embed"
|
get "/posts/:id/expand-embed" => "posts#expand_embed"
|
||||||
get "raw/:topic_id(/:post_number)" => "posts#markdown"
|
get "raw/:topic_id(/:post_number)" => "posts#markdown"
|
||||||
|
|
||||||
resources :invites
|
resources :invites do
|
||||||
|
collection do
|
||||||
|
get "upload" => "invites#check_csv_chunk"
|
||||||
|
post "upload" => "invites#upload_csv_chunk"
|
||||||
|
end
|
||||||
|
end
|
||||||
delete "invites" => "invites#destroy"
|
delete "invites" => "invites#destroy"
|
||||||
|
|
||||||
get "onebox" => "onebox#show"
|
get "onebox" => "onebox#show"
|
||||||
|
|
|
@ -204,6 +204,10 @@ class Guardian
|
||||||
( group_ids.blank? || is_admin? )
|
( group_ids.blank? || is_admin? )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def can_bulk_invite_to_forum?(user)
|
||||||
|
user.admin?
|
||||||
|
end
|
||||||
|
|
||||||
def can_see_private_messages?(user_id)
|
def can_see_private_messages?(user_id)
|
||||||
is_admin? || (authenticated? && @user.id == user_id)
|
is_admin? || (authenticated? && @user.id == user_id)
|
||||||
end
|
end
|
||||||
|
|
|
@ -56,5 +56,3 @@ if User.count == 0
|
||||||
puts
|
puts
|
||||||
puts "To get started run: bundle exec thin start"
|
puts "To get started run: bundle exec thin start"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -148,6 +148,65 @@ describe InvitesController do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context '.check_csv_chunk' do
|
||||||
|
it 'requires you to be logged in' do
|
||||||
|
lambda {
|
||||||
|
post :check_csv_chunk
|
||||||
|
}.should raise_error(Discourse::NotLoggedIn)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'while logged in' do
|
||||||
|
let(:resumableChunkNumber) { 1 }
|
||||||
|
let(:resumableCurrentChunkSize) { 46 }
|
||||||
|
let(:resumableIdentifier) { '46-discoursecsv' }
|
||||||
|
let(:resumableFilename) { 'discourse.csv' }
|
||||||
|
|
||||||
|
it "fails if you can't bulk invite to the forum" do
|
||||||
|
log_in
|
||||||
|
post :check_csv_chunk, resumableChunkNumber: resumableChunkNumber, resumableCurrentChunkSize: resumableCurrentChunkSize.to_i, resumableIdentifier: resumableIdentifier, resumableFilename: resumableFilename
|
||||||
|
response.should_not be_success
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context '.upload_csv_chunk' do
|
||||||
|
it 'requires you to be logged in' do
|
||||||
|
lambda {
|
||||||
|
post :upload_csv_chunk
|
||||||
|
}.should raise_error(Discourse::NotLoggedIn)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'while logged in' do
|
||||||
|
let(:csv_file) { File.new("#{Rails.root}/spec/fixtures/csv/discourse.csv") }
|
||||||
|
let(:file) do
|
||||||
|
ActionDispatch::Http::UploadedFile.new({ filename: 'discourse.csv', tempfile: csv_file })
|
||||||
|
end
|
||||||
|
let(:resumableChunkNumber) { 1 }
|
||||||
|
let(:resumableChunkSize) { 1048576 }
|
||||||
|
let(:resumableCurrentChunkSize) { 46 }
|
||||||
|
let(:resumableTotalSize) { 46 }
|
||||||
|
let(:resumableType) { 'text/csv' }
|
||||||
|
let(:resumableIdentifier) { '46-discoursecsv' }
|
||||||
|
let(:resumableFilename) { 'discourse.csv' }
|
||||||
|
let(:resumableRelativePath) { 'discourse.csv' }
|
||||||
|
|
||||||
|
it "fails if you can't bulk invite to the forum" do
|
||||||
|
log_in
|
||||||
|
post :upload_csv_chunk, file: file, resumableChunkNumber: resumableChunkNumber.to_i, resumableChunkSize: resumableChunkSize.to_i, resumableCurrentChunkSize: resumableCurrentChunkSize.to_i, resumableTotalSize: resumableTotalSize.to_i, resumableType: resumableType, resumableIdentifier: resumableIdentifier, resumableFilename: resumableFilename
|
||||||
|
response.should_not be_success
|
||||||
|
end
|
||||||
|
|
||||||
|
it "allows admins to bulk invite" do
|
||||||
|
log_in(:admin)
|
||||||
|
post :upload_csv_chunk, file: file, resumableChunkNumber: resumableChunkNumber.to_i, resumableChunkSize: resumableChunkSize.to_i, resumableCurrentChunkSize: resumableCurrentChunkSize.to_i, resumableTotalSize: resumableTotalSize.to_i, resumableType: resumableType, resumableIdentifier: resumableIdentifier, resumableFilename: resumableFilename
|
||||||
|
response.should be_success
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
jeff@gmail.com
sam@yahoo.com
robin@outlook.com
neil@aol.com
regis@live.com
|
|
Loading…
Reference in New Issue