Skip to content

Commit

Permalink
Merge pull request #79 from krlxfm/0.7.0
Browse files Browse the repository at this point in the history
0.7.0
  • Loading branch information
tatebosler authored Jul 30, 2018
2 parents 73d36a9 + d45316c commit 2ca6a3c
Show file tree
Hide file tree
Showing 53 changed files with 1,236 additions and 231 deletions.
4 changes: 1 addition & 3 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
* text=auto
*.css linguist-vendored
*.scss linguist-vendored
*.js linguist-vendored
public/* linguist-vendored
CHANGELOG.md export-ignore
97 changes: 97 additions & 0 deletions app/Http/Controllers/API/ShowController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@

use KRLX\Show;
use KRLX\User;
use Validator;
use Illuminate\Http\Request;
use KRLX\Rulesets\ShowRuleset;
use Illuminate\Validation\Rule;
use KRLX\Http\Controllers\Controller;
use KRLX\Notifications\ShowSubmitted;
use KRLX\Notifications\ShowInvitation;
use KRLX\Http\Requests\ShowUpdateRequest;
use KRLX\Notifications\NewUserShowInvitation;
use Illuminate\Contracts\Encryption\DecryptException;

class ShowController extends Controller
{
Expand Down Expand Up @@ -91,6 +97,35 @@ public function destroy(Show $show)
return response(null, 204);
}

/**
* Invite a host who does not have a user account.
*
* @param Illuminate\Http\Request $request
* @param KRLX\Show $show
* @return Illuminate\Http\Response
*/
public function inviteHostWithoutUserAccount(Request $request, Show $show)
{
$request->validate([
'invite' => 'array',
'invite.*' => 'email|distinct',
]);

foreach ($request->input('invite') as $new_email) {
$host = User::where('email', $new_email)->first();

if (! $host) {
// Create a temporary user so that we can send the email.
// This user will be deleted in about 3 seconds anyway.
$host = User::create(['email' => $new_email, 'name' => 'Temporary User', 'password' => '']);
$host->notify(new NewUserShowInvitation($show, $request->user()));
$host->delete();
}
}

return $show;
}

/**
* Manage the hosts of a show.
*
Expand All @@ -112,6 +147,7 @@ public function changeHosts(Request $request, Show $show)

if (! ($show->hosts->contains($host) or $show->invitees->contains($host))) {
$show->invitees()->attach($host->id);
$host->notify(new ShowInvitation($show, $request->user()));
}
}

Expand All @@ -124,4 +160,65 @@ public function changeHosts(Request $request, Show $show)

return $show;
}

/**
* Respond to a join invitation.
*
* @param Illuminate\Http\Request $request
* @param KRLX\Show $show
* @return Illuminate\Http\Response
*/
public function join(Request $request, Show $show)
{
$request->validate(['token' => 'required|string']); // (1)
try {
$data = decrypt($request->input('token')); // (2)
if (! is_array($data)) { // (3)
throw new DecryptException('The given token is not an array.');
} elseif (! array_key_exists('show', $data) or ! array_key_exists('user', $data)) { // (4)
throw new DecryptException('The token does not have the required components.');
} elseif ($data['user'] != $request->user()->email) { // (5)
throw new DecryptException('The token does not belong to you.');
} elseif ($data['show'] != $show->id) { // (6)
throw new DecryptException('The token does not belong to this show.');
}
} catch (DecryptException $e) {
abort(400, 'The token is invalid.');
}

// We now know that: (1) the token is present, (2) it is encrypted,
// (3) the decrypted form is an array, (4) it has the required
// components, (5) it belongs to the user, and (6) it belongs to the
// show being joined. This request is therefore authorized and we can
// now make the connection.
$show->invitees()->detach($request->user()->id);
$show->hosts()->detach($request->user()->id);
$show->hosts()->attach($request->user()->id, ['accepted' => true]);

return $show;
}

/**
* Respond to a join invitation.
* Validate a show and submit it, or remove submission status.
*
* @param Illuminate\Http\Request $request
* @param KRLX\Show $show
* @return Illuminate\Http\Response
*/
public function submit(Request $request, Show $show)
{
if ($request->input('submitted') and ! $show->submitted) {
$ruleset = new ShowRuleset($show, $request->all());
$rules = $ruleset->rules(true);

Validator::make($show->toArray(), $rules)->validate();

$request->user()->notify(new ShowSubmitted($show));
}
$show->submitted = $request->input('submitted') ?? false;
$show->save();

return $show;
}
}
48 changes: 47 additions & 1 deletion app/Http/Controllers/ShowController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@

use KRLX\Show;
use KRLX\Term;
use Validator;
use KRLX\Track;
use Illuminate\Http\Request;
use KRLX\Rulesets\ShowRuleset;
use Illuminate\Validation\Rule;
use KRLX\Http\Controllers\API\ShowController as APIController;

class ShowController extends Controller
{
Expand Down Expand Up @@ -93,7 +96,16 @@ public function hosts(Show $show)
*/
public function content(Show $show)
{
return view('shows.content', compact('show'));
$ruleset = new ShowRuleset($show, []);
$rules = collect($ruleset->rules(true));
$keys = array_merge(['title', 'description', 'content'], $rules->filter(function ($value, $key) {
return starts_with($key, 'content.');
})->keys()->all());

$validator = Validator::make($show->toArray(), $rules->only($keys)->all());
$initialErrors = $validator->errors()->messages();

return view('shows.content', compact('show', 'initialErrors'));
}

/**
Expand Down Expand Up @@ -173,4 +185,38 @@ public function djs(Request $request, Term $term = null)

return view('shows.djs', compact('term', 'terms', 'users'));
}

/**
* Display the "Join Show" view.
*
* @param KRLX\Show|null $show
* @return Illuminate\Http\Response
*/
public function join(Show $show = null)
{
if ($show == null) {
return view('shows.find');
} else {
return view('shows.join', compact('show'));
}
}

/**
* Process a join request.
*
* @param Illuminate\Http\Request $request
* @param KRLX\Show|null $show
* @return Illuminate\Http\Response
*/
public function processJoinRequest(Request $request, Show $show)
{
$controller = new APIController();

// Throws an HTTP 400 if a bad token comes in.
$controller->join($request, $show);

$request->session()->flash('success', "You have successfully joined {$show->title}! Please carefully review the schedule below and add your details if necessary.");

return redirect()->route('shows.schedule', $show);
}
}
115 changes: 3 additions & 112 deletions app/Http/Requests/ShowUpdateRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace KRLX\Http\Requests;

use KRLX\Track;
use KRLX\Rules\Profanity;
use KRLX\Rulesets\ShowRuleset;
use Illuminate\Foundation\Http\FormRequest;

class ShowUpdateRequest extends FormRequest
Expand All @@ -26,117 +26,8 @@ public function authorize()
public function rules()
{
$track = Track::find($this->input('track_id')) ?? $this->show->track;
$rules = array_merge(
$this->baseRules(),
$this->trackDependentRules($track),
$this->customFieldRules($track)
);
$ruleset = new ShowRuleset($this->show, $this->all(), $track);

if ($this->isMethod('PUT')) {
foreach ($rules as $field => &$ruleset) {
$ruleset = array_prepend($ruleset, (head($ruleset) == 'nullable' or in_array('min:0', $ruleset)) ? 'present' : 'required');
}
}

return $rules;
}

/**
* Returns the "base" rules, applicable to all tracks.
*
* @return array
*/
protected function baseRules()
{
$baseRules = [
'submitted' => ['boolean'],
'title' => ['string', 'min:3', 'max:200', new Profanity],
'content' => ['array'],
'scheduling' => ['array'],
'conflicts' => ['array', 'min:0'],
'preferences' => ['array'],
'etc' => ['array'],
'special_times' => ['array', 'size:'.count(config('defaults.special_times'))],
'classes' => ['array'],
'classes.*' => ['string'],
'tags.*' => ['string'],
'preferred_length' => ['integer', 'min:0', 'max:240'],
'notes' => ['nullable', 'string', 'max:65000'],
'date' => ['nullable', 'date'],
'day' => ['nullable', 'string', 'in:Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'],
'start' => ['nullable', 'string', 'regex:([01][0-9]|2[0-3]):[0-5][0-9]'],
'end' => ['nullable', 'string', 'regex:([01][0-9]|2[0-3]):[0-5][0-9]'],
];

foreach (config('defaults.special_times') as $time => $details) {
$baseRules["special_times.$time"] = ['string', 'in:y,m,n'];
}

return $baseRules;
}

/**
* Returns the basic which change based on the track settings.
* (These aren't the custom fields.).
*
* @param KRLX\Track $track
* @return array
*/
protected function trackDependentRules(Track $track)
{
$trackDepRules = [
'description' => ['min:'.$track->description_min_length, 'max:65000'],
'conflicts.*' => ($track->weekly ? ['array'] : ['date', 'distinct']),
'preferences.*' => ($track->weekly ? ['array'] : ['date', 'distinct']),
'tags' => ['array', ($track->taggable ? 'min:0' : 'max:0')],
];

if ($track->weekly) {
$trackDepRules['conflicts.*.days'] = ['array', 'min:1', 'max:7', 'distinct'];
$trackDepRules['conflicts.*.days.*'] = ['string', 'in:Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'];
$trackDepRules['conflicts.*.start'] = ['string', 'regex:/([01][0-9]|2[0-3]):[03]0/'];
$trackDepRules['conflicts.*.end'] = ['string', 'regex:/([01][0-9]|2[0-3]):[03]0/'];
$trackDepRules['preferences.*.days'] = ['array', 'min:1', 'max:7', 'distinct'];
$trackDepRules['preferences.*.days.*'] = ['string', 'in:Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'];
$trackDepRules['preferences.*.start'] = ['string', 'regex:/([01][0-9]|2[0-3]):[03]0/'];
$trackDepRules['preferences.*.end'] = ['string', 'regex:/([01][0-9]|2[0-3]):[03]0/'];
$trackDepRules['preferences.*.strength'] = ['integer', 'min:0', 'max:200'];
}

return $trackDepRules;
}

/**
* Returns the rules for custom fields.
*
* @param KRLX\Track $track
* @return array
*/
protected function customFieldRules(Track $track)
{
$custom = ['content', 'scheduling', 'etc'];
$rules = [];
foreach ($custom as $category) {
foreach ($track->{$category} as $field) {
$rules[$category.'.'.$field['db']] = $this->processCustomFieldRules($field['rules']);
}
}

return $rules;
}

/**
* Process the validation rules for a given custom field.
*
* @param array $rules
* @return array
*/
protected function processCustomFieldRules(array $rules)
{
$filtered_rules = array_where($rules, function ($value, $key) {
return $value != 'required';
});

return $filtered_rules;
return $ruleset->rules($this->isMethod('PUT'));
}
}
36 changes: 36 additions & 0 deletions app/Mail/ShowSubmitted.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace KRLX\Mail;

use KRLX\Show;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class ShowSubmitted extends Mailable
{
use Queueable, SerializesModels;

public $show;

/**
* Create a new message instance.
*
* @return void
*/
public function __construct(Show $show)
{
$this->show = $show;
}

/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->markdown('mail.shows.submitted')
->with(['show' => $this->show]);
}
}
Loading

0 comments on commit 2ca6a3c

Please sign in to comment.