Initial Spark Install

This commit is contained in:
Deon George
2017-11-03 16:26:07 +11:00
commit b1a5807eb3
766 changed files with 128896 additions and 0 deletions

View File

@@ -0,0 +1,102 @@
<?php
namespace Laravel\Spark\Http\Controllers\Auth;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Foundation\Auth\RedirectsUsers;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Interactions\Settings\Security\DisableTwoFactorAuth;
class EmergencyLoginController extends Controller
{
use RedirectsUsers;
/**
* Create a new emergency login controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
$this->middleware('throttle:3,1')->only('login');
}
/**
* Show the form to login via the emergency token.
*
* @param Request $request
* @return Response
*/
public function showLoginForm(Request $request)
{
return $request->session()->has('spark:auth:id')
? view('spark::auth.login-via-emergency-token')
: redirect('login');
}
/**
* Login via the emergency token.
*
* @param Request $request
* @return Response
*/
public function login(Request $request)
{
$this->validate($request, [
'token' => 'required',
]);
// If there is no authentication ID stored in the session, it means that the user
// hasn't made it through the login screen so we'll just redirect them back to
// the login view. They must have hit the route manually via a specific URL.
if (! $request->session()->has('spark:auth:id')) {
return redirect('login');
}
$user = Spark::user()->findOrFail(
$request->session()->pull('spark:auth:id')
);
// Here we will check this hash of the token against the stored hash of the reset
// token to make sure they match. If they don't match then the emergency token
// is invalid so we'll redirect back out with an error message for the user.
$resetCode = $user->two_factor_reset_code;
if (! Hash::check($request->token, $resetCode)) {
return redirect('login')->withErrors([
'token' => 'The emergency token was invalid.'
]);
}
// If the token was valid we will login this user after disabling the two-factor
// authentication settings so that they don't get stuck again. They will then
// re-enable two-factor authentication in their settings if they so choose.
$this->disableTwoFactorAuth($user);
Auth::login($user, $request->session()->pull(
'spark:auth:remember', false
));
return redirect()->intended($this->redirectPath());
}
/**
* Disable two-factor authentication for the given user.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @return void
*/
protected function disableTwoFactorAuth($user)
{
Spark::interact(DisableTwoFactorAuth::class, [$user]);
$user->forceFill([
'uses_two_factor_auth' => false,
])->save();
}
}

View File

@@ -0,0 +1,159 @@
<?php
namespace Laravel\Spark\Http\Controllers\Auth;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Laravel\Spark\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Laravel\Spark\Contracts\Interactions\Settings\Security\VerifyTwoFactorAuthToken as Verify;
class LoginController extends Controller
{
use AuthenticatesUsers {
AuthenticatesUsers::login as traitLogin;
}
/**
* Create a new login controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
$this->redirectTo = Spark::afterLoginRedirect();
}
/**
* Show the application login form.
*
* @return \Illuminate\Http\Response
*/
public function showLoginForm()
{
return view('spark::auth.login');
}
/**
* {@inheritdoc}
*/
public function login(Request $request)
{
if ($request->filled('remember')) {
$request->session()->put('spark:auth-remember', $request->remember);
}
$user = Spark::user()->where('email', $request->email)->first();
if (Spark::usesTwoFactorAuth() && $user && $user->uses_two_factor_auth) {
$request->merge(['remember' => '']);
}
return $this->traitLogin($request);
}
/**
* Handle a successful authentication attempt.
*
* @param Request $request
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @return Response
*/
public function authenticated(Request $request, $user)
{
if (Spark::usesTwoFactorAuth() && $user->uses_two_factor_auth) {
return $this->redirectForTwoFactorAuth($request, $user);
}
return redirect()->intended($this->redirectPath());
}
/**
* Redirect the user for two-factor authentication.
*
* @param Request $request
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @return Response
*/
protected function redirectForTwoFactorAuth(Request $request, $user)
{
Auth::logout();
// Before we redirect the user to the two-factor token verification screen we will
// store this user's ID and "remember me" choice in the session so that we will
// be able to get it back out and log in the correct user after verification.
$request->session()->put([
'spark:auth:id' => $user->id,
'spark:auth:remember' => $request->remember,
]);
return redirect('login/token');
}
/**
* Show the two-factor authentication token form.
*
* @param Request $request
* @return Response
*/
public function showTokenForm(Request $request)
{
return $request->session()->has('spark:auth:id')
? view('spark::auth.token') : redirect('login');
}
/**
* Verify the given authentication token.
*
* @param Request $request
* @return Response
*/
public function verifyToken(Request $request)
{
$this->validate($request, ['token' => 'required']);
// If there is no authentication ID stored in the session, it means that the user
// hasn't made it through the login screen so we'll just redirect them back to
// the login view. They must have hit the route manually via a specific URL.
if (! $request->session()->has('spark:auth:id')) {
return redirect('login');
}
$user = Spark::user()->findOrFail(
$request->session()->pull('spark:auth:id')
);
// Next, we'll verify the actual token with our two-factor authentication service
// to see if the token is valid. If it is, we can login the user and send them
// to their intended location within the protected part of this application.
if (Spark::interact(Verify::class, [$user, $request->token])) {
Auth::login($user, $request->session()->pull(
'spark:auth:remember', false
));
return redirect()->intended($this->redirectPath());
} else {
return back();
}
}
/**
* Log the user out of the application.
*
* @return \Illuminate\Http\Response
*/
public function logout()
{
$this->guard()->logout();
session()->flush();
return redirect(
property_exists($this, 'redirectAfterLogout')
? $this->redirectAfterLogout : '/'
);
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace Laravel\Spark\Http\Controllers\Auth;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
class PasswordController extends Controller
{
use SendsPasswordResetEmails, ResetsPasswords {
SendsPasswordResetEmails::broker insteadof ResetsPasswords;
}
/**
* Create a new password controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
$this->middleware('throttle:3,1')->only('sendResetLinkEmail', 'reset');
$this->redirectTo = Spark::afterLoginRedirect();
}
/**
* Display the form to request a password reset link.
*
* @return \Illuminate\Http\Response
*/
public function showLinkRequestForm()
{
return view('spark::auth.passwords.email');
}
/**
* Display the password reset view for the given token.
*
* If no token is present, display the link request form.
*
* @param \Illuminate\Http\Request $request
* @param string|null $token
* @return \Illuminate\Http\Response
*/
public function showResetForm(Request $request, $token = null)
{
if (is_null($token)) {
return $this->showLinkRequestForm();
}
return view('spark::auth.passwords.reset')
->with(['token' => $token, 'email' => $request->email]);
}
}

View File

@@ -0,0 +1,68 @@
<?php
namespace Laravel\Spark\Http\Controllers\Auth;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Laravel\Spark\Events\Auth\UserRegistered;
use Laravel\Spark\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\RedirectsUsers;
use Laravel\Spark\Contracts\Interactions\Auth\Register;
use Laravel\Spark\Contracts\Http\Requests\Auth\RegisterRequest;
class RegisterController extends Controller
{
use RedirectsUsers;
/**
* Create a new authentication controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('guest');
$this->redirectTo = Spark::afterLoginRedirect();
}
/**
* Show the application registration form.
*
* @param Request $request
* @return Response
*/
public function showRegistrationForm(Request $request)
{
if (Spark::promotion() && ! $request->filled('coupon')) {
// If the application is running a site-wide promotion, we will redirect the user
// to a register URL that contains the promotional coupon ID, which will force
// all new registrations to use this coupon when creating the subscriptions.
return redirect($request->fullUrlWithQuery([
'coupon' => Spark::promotion()
]));
}
return view('spark::auth.register');
}
/**
* Handle a registration request for the application.
*
* @param RegisterRequest $request
* @return Response
*/
public function register(RegisterRequest $request)
{
Auth::login($user = Spark::interact(
Register::class, [$request]
));
event(new UserRegistered($user));
return response()->json([
'redirect' => $this->redirectPath()
]);
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Laravel\Spark\Http\Controllers;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
class Controller extends BaseController
{
use ValidatesRequests;
/**
* Execute the given interaction.
*
* This performs the common validate and handle flow of some interactions.
*
* @param Request $request
* @param string $interaction
* @param array $parameters
* @return void
*/
public function interaction(Request $request, $interaction, array $parameters)
{
Spark::interact($interaction.'@validator', $parameters)->validate();
return Spark::interact($interaction, $parameters);
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace Laravel\Spark\Http\Controllers;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Contracts\Repositories\CouponRepository;
class CouponController extends Controller
{
/**
* The coupon repository implementation.
*
* @var \Laravel\Spark\Contracts\Repositories\CouponRepository
*/
protected $coupons;
/**
* Create a new controller instance.
*
* @param \Laravel\Spark\Contracts\Repositories\CouponRepository $coupons
* @return void
*/
public function __construct(CouponRepository $coupons)
{
$this->coupons = $coupons;
$this->middleware('auth', ['only' => 'current']);
}
/**
* Get the specified coupon from Stripe.
*
* This is used during registration to show the discount.
*
* @param string $code
* @return Response
*/
public function show($code)
{
$coupon = $this->coupons->find($code);
return $coupon ? response()->json($coupon->toArray()) : abort(404);
}
/**
* Get the current discount for the given user.
*
* @param Request $request
* @param string $userId
* @return Response
*/
public function current(Request $request, $userId)
{
$user = Spark::user()->where('id', $userId)->firstOrFail();
if ($coupon = $this->coupons->forBillable($user)) {
return response()->json($coupon->toArray());
}
abort(204);
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace Laravel\Spark\Http\Controllers;
use Exception;
use Illuminate\Http\Request;
use GuzzleHttp\Client as HttpClient;
use Laravel\Spark\Contracts\Repositories\Geography\StateRepository;
class GeocodingController extends Controller
{
/**
* Attempt to gather the current user's country via Geocoding.
*
* @param Request $request
* @return Response
*/
public function country(Request $request)
{
try {
$response = (new HttpClient)->get('http://ip2c.org/?ip='.$request->ip());
$body = (string) $response->getBody();
if ($body[0] === '1') {
return explode(';', $body)[1];
}
} catch (Exception $e) {
return response('', 404);
}
}
/**
* Get the states / provinces for a given country code.
*
* @param string $country
* @return Response
*/
public function states($country)
{
return response()->json(app(StateRepository::class)->forCountry($country)->all());
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Laravel\Spark\Http\Controllers;
use Laravel\Spark\Invitation;
class InvitationController extends Controller
{
/**
* Get the given invitation.
*
* This is used during registration to show the invitation.
*
* @param string $token
* @return Response
*/
public function show($token)
{
$invitation = Invitation::with('team')->where('token', $token)->firstOrFail();
if ($invitation->isExpired()) {
$invitation->delete();
abort(404);
}
return $invitation;
}
}

View File

@@ -0,0 +1,92 @@
<?php
namespace Laravel\Spark\Http\Controllers\Kiosk;
use Illuminate\Http\Request;
use Laravel\Spark\Announcement;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Repositories\AnnouncementRepository;
class AnnouncementController extends Controller
{
/**
* The announcements repository.
*
* @param \Laravel\Spark\Contracts\Repositories\AnnouncementRepository
*/
protected $announcements;
/**
* Create a new controller instance.
*
* @param \Laravel\Spark\Contracts\Repositories\AnnouncementRepository $announcements
* @return void
*/
public function __construct(AnnouncementRepository $announcements)
{
$this->announcements = $announcements;
$this->middleware('auth');
$this->middleware('dev');
}
/**
* Get all of the application's recent announcements.
*
* @return Response
*/
public function all()
{
return $this->announcements->recent();
}
/**
* Create a new announcement.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$this->validate($request, [
'body' => 'required',
'action_text' => 'required_with:action_url|max:255',
'action_url' => 'required_with:action_text',
]);
$this->announcements->create(
$request->user(), $request->all()
);
}
/**
* Update the given announcement.
*
* @param Request $request
* @param string $id
* @return Response
*/
public function update(Request $request, $id)
{
$this->validate($request, [
'body' => 'required',
'action_text' => 'max:255',
'action_url' => 'required_with:action_text',
]);
$this->announcements->update(
Announcement::findOrFail($id), $request->all()
);
}
/**
* Delete the announcement with the given ID.
*
* @param string $id
* @return Response
*/
public function destroy($id)
{
Announcement::findOrFail($id)->delete();
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace Laravel\Spark\Http\Controllers\Kiosk;
use Laravel\Spark\Http\Controllers\Controller;
class DashboardController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('dev');
}
/**
* Show the kiosk dashboard.
*
* @return Response
*/
public function show()
{
return view('spark::kiosk');
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace Laravel\Spark\Http\Controllers\Kiosk;
use Laravel\Spark\Spark;
use Laravel\Cashier\Cashier;
use Illuminate\Http\Request;
use Stripe\Coupon as StripeCoupon;
use Laravel\Spark\Http\Controllers\Controller;
class DiscountController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('dev');
}
/**
* Create a discount for the given user.
*
* @param Request $request
* @param string $userId
* @return Response
*/
public function store(Request $request, $userId)
{
$user = Spark::user()->where('id', $userId)->firstOrFail();
$this->validate($request, [
'type' => 'required|in:amount,percent',
'value' => 'required|integer',
'duration' => 'required|in:once,forever,repeating',
'months' => 'required_if:duration,repeating',
]);
$coupon = StripeCoupon::create([
'currency' => Cashier::usesCurrency(),
'amount_off' => $request->type == 'amount' ? $request->value * 100 : null,
'percent_off' => $request->type == 'percent' ? $request->value : null,
'duration' => $request->duration,
'duration_in_months' => $request->months,
'max_redemptions' => 1,
], config('services.stripe.secret'));
$user->applyCoupon($coupon->id);
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace Laravel\Spark\Http\Controllers\Kiosk;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Laravel\Spark\Http\Controllers\Controller;
class ImpersonationController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('dev')->except('stopImpersonating');
}
/**
* Impersonate the given user.
*
* @param Request $request
* @param string $userId
* @return Response
*/
public function impersonate(Request $request, $userId)
{
$request->session()->flush();
// We will store the original user's ID in the session so we can remember who we
// actually are when we need to stop impersonating the other user, which will
// allow us to pull the original user back out of the database when needed.
$request->session()->put(
'spark:impersonator', $request->user()->id
);
Auth::login(Spark::user()->findOrFail($userId));
return redirect('/settings');
}
/**
* Stop impersonating and switch back to primary account.
*
* @param Request $request
* @return Response
*/
public function stopImpersonating(Request $request)
{
$currentId = Auth::id();
// We will make sure we have an impersonator's user ID in the session and if the
// value doesn't exist in the session we will log this user out of the system
// since they aren't really impersonating anyone and manually hit this URL.
if (! $request->session()->has('spark:impersonator')) {
Auth::logout();
return redirect('/');
}
$userId = $request->session()->pull(
'spark:impersonator'
);
// After removing the impersonator user's ID from the session so we can retrieve
// the original user. Then, we will flush the entire session to clear out any
// stale data from while we were doing the impersonation of the other user.
$request->session()->flush();
Auth::login(Spark::user()->findOrFail($userId));
return redirect('/spark/kiosk#/users/'.$currentId);
}
}

View File

@@ -0,0 +1,96 @@
<?php
namespace Laravel\Spark\Http\Controllers\Kiosk;
use Carbon\Carbon;
use Laravel\Spark\Spark;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Repositories\PerformanceIndicatorsRepository;
class PerformanceIndicatorsController extends Controller
{
/**
* The performance indicators repository instance.
*
* @var PerformanceIndicatorsRepository
*/
protected $indicators;
/**
* Create a new controller instance.
*
* @param PerformanceIndicatorsRepository $indicators
* @return void
*/
public function __construct(PerformanceIndicatorsRepository $indicators)
{
$this->indicators = $indicators;
$this->middleware('auth');
$this->middleware('dev');
}
/**
* Get the performance indicators for the application.
*
* @return Response
*/
public function all()
{
return response()->json([
'indicators' => $this->indicators->all(60),
'last_month' => $this->indicators->forDate(Carbon::today()->subMonths(1)),
'last_year' => $this->indicators->forDate(Carbon::today()->subYears(1)),
]);
}
/**
* Get the revenue amounts for the application.
*
* @return Response
*/
public function revenue()
{
return [
'yearlyRecurringRevenue' => $this->indicators->yearlyRecurringRevenue(),
'monthlyRecurringRevenue' => $this->indicators->monthlyRecurringRevenue(),
'totalVolume' => $this->indicators->totalVolume(),
];
}
/**
* Get the subscriber counts by plan.
*
* @return Response
*/
public function subscribers()
{
$plans = [];
foreach (Spark::allPlans() as $plan) {
$plans[] = [
'name' => $plan->name,
'interval' => $plan->interval,
'count' => $this->indicators->subscribers($plan),
'trialing' => $this->indicators->trialing($plan),
];
}
return collect($plans)->sortByDesc('count')->values()->all();
}
/**
* Get the number of users or teams who are on a generic trial.
*
* @return Response
*/
public function trials()
{
$model = Spark::teamTrialDays() ? Spark::team() : Spark::user();
return $model
->where('trial_ends_at', '>=', Carbon::now())
->whereDoesntHave('subscriptions')
->count();
}
}

View File

@@ -0,0 +1,50 @@
<?php
namespace Laravel\Spark\Http\Controllers\Kiosk;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Repositories\UserRepository;
use Laravel\Spark\Contracts\Repositories\PerformanceIndicatorsRepository;
class ProfileController extends Controller
{
/**
* The performance indicators repository instance.
*
* @var PerformanceIndicatorsRepository
*/
protected $indicators;
/**
* Create a new controller instance.
*
* @param PerformanceIndicatorsRepository $indicators
* @return void
*/
public function __construct(PerformanceIndicatorsRepository $indicators)
{
$this->indicators = $indicators;
$this->middleware('auth');
$this->middleware('dev');
}
/**
* Get the user to be displayed on the user profile screen.
*
* @param Request $request
* @param string $id
* @return Response
*/
public function show(Request $request, $id)
{
$user = Spark::call(UserRepository::class.'@find', [$id]);
return response()->json([
'user' => $user,
'revenue' => $this->indicators->totalRevenueForUser($user),
]);
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Laravel\Spark\Http\Controllers\Kiosk;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Repositories\UserRepository;
class SearchController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('dev');
}
/**
* Get the users based on the incoming search query.
*
* @param Request $request
* @return Response
*/
public function performBasicSearch(Request $request)
{
$query = str_replace('*', '%', $request->input('query'));
return Spark::interact(UserRepository::class.'@search', [
$query, $request->user()
]);
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace Laravel\Spark\Http\Controllers;
class MissingTeamController extends Controller
{
/**
* Show the missing team notice.
*
* @return Response
*/
public function show()
{
return view('spark::missing-team');
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace Laravel\Spark\Http\Controllers;
use Illuminate\Http\Request;
use Laravel\Spark\Notification;
use Laravel\Spark\Contracts\Repositories\NotificationRepository;
use Laravel\Spark\Contracts\Repositories\AnnouncementRepository;
class NotificationController extends Controller
{
/**
* The announcements repository.
*
* @var AnnouncementRepository
*/
protected $announcements;
/**
* The notifications repository.
*
* @var NotificationRepository
*/
protected $notifications;
/**
* Create a new controller instance.
*
* @param AnnouncementRepository $announcements
* @param NotificationRepository $notifications
* @return void
*/
public function __construct(AnnouncementRepository $announcements,
NotificationRepository $notifications)
{
$this->announcements = $announcements;
$this->notifications = $notifications;
$this->middleware('auth');
}
/**
* Get the recent notifications and announcements for the user.
*
* @param Request $request
* @return Response
*/
public function recent(Request $request)
{
return response()->json([
'announcements' => $this->announcements->recent()->toArray(),
'notifications' => $this->notifications->recent($request->user())->toArray(),
]);
}
/**
* Mark the given notifications as read.
*
* @param Request $request
* @return Response
*/
public function markAsRead(Request $request)
{
Notification::whereIn('id', $request->notifications)->whereUserId($request->user()->id)->update(['read' => 1]);
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Laravel\Spark\Http\Controllers;
use Laravel\Spark\Spark;
class PlanController extends Controller
{
/**
* Get the all of the regular plans defined for the application.
*
* @return Response
*/
public function all()
{
return response()->json(Spark::allPlans());
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\API;
use Laravel\Spark\Spark;
use Laravel\Spark\Http\Controllers\Controller;
class TokenAbilitiesController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Get all of the available token abilities.
*
* @return Response
*/
public function all()
{
return response()->json(collect(Spark::tokensCan())->map(function ($value, $key) {
return [
'name' => $value,
'value' => $key,
'default' => in_array($key, Spark::tokenDefaults())
];
})->values());
}
}

View File

@@ -0,0 +1,96 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\API;
use Laravel\Spark\Token;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Repositories\TokenRepository;
use Laravel\Spark\Http\Requests\Settings\API\CreateTokenRequest;
use Laravel\Spark\Http\Requests\Settings\API\UpdateTokenRequest;
class TokenController extends Controller
{
/**
* The token repository instance.
*
* @var TokenRepository
*/
protected $tokens;
/**
* Create a new controller instance.
*
* @param TokenRepository $tokens
* @return void
*/
public function __construct(TokenRepository $tokens)
{
$this->tokens = $tokens;
$this->middleware('auth');
}
/**
* Get all of the tokens generated by the user.
*
* @param Request $request
* @return Response
*/
public function all(Request $request)
{
return $this->tokens->all($request->user());
}
/**
* Create a new API token for the user.
*
* @param CreateTokenRequest $request
* @return Response
*/
public function store(CreateTokenRequest $request)
{
$data = count(Spark::tokensCan()) > 0 ? ['abilities' => $request->abilities] : [];
return response()->json(['token' => $this->tokens->createToken(
$request->user(), $request->name, $data
)->token]);
}
/**
* Update the given API token.
*
* @param UpdateTokenRequest $request
* @param string $tokenId
* @return Response
*/
public function update(UpdateTokenRequest $request, $tokenId)
{
$token = $request->user()->tokens()->where('id', $tokenId)->firstOrFail();
if (class_exists('Laravel\Passport\Passport')) {
$token = new Token([
'id' => $token->id,
'name' => $token->name,
'metadata' => ['abilities' => $token->scopes],
]);
}
$this->tokens->updateToken(
$token, $request->name, (array) $request->abilities
);
}
/**
* Delete the given token.
*
* @param Request $request
* @param string $tokenId
* @return Response
*/
public function destroy(Request $request, $tokenId)
{
$request->user()->tokens()->where('id', $tokenId)->firstOrFail()->delete();
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Billing;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
class BillingInformationController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Update the user's extra billing information.
*
* @param Request $request
* @return Response
*/
public function update(Request $request)
{
$this->validate($request, [
'information' => 'max:2048',
]);
$request->user()->forceFill([
'extra_billing_information' => $request->information,
])->save();
}
}

View File

@@ -0,0 +1,112 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Billing;
use Illuminate\Http\Response;
use Braintree\WebhookNotification;
use Laravel\Spark\TeamSubscription;
use Laravel\Cashier\Http\Controllers\WebhookController;
use Laravel\Spark\Events\Subscription\SubscriptionCancelled;
use Laravel\Spark\Contracts\Repositories\LocalInvoiceRepository;
use Laravel\Spark\Events\Teams\Subscription\SubscriptionCancelled as TeamSubscriptionCancelled;
class BraintreeWebhookController extends WebhookController
{
use SendsInvoiceNotifications;
/**
* Handle a successful invoice payment from a Braintree subscription.
*
* By default, this e-mails a copy of the invoice to the customer.
*
* @param WebhookNotification $webhook
* @return Response
*/
protected function handleSubscriptionChargedSuccessfully($webhook)
{
$subscription = $this->getSubscriptionById($webhook->subscription->id);
if (! $subscription || ! isset($webhook->subscription->transactions[0])) {
return $this->teamSubscriptionChargedSuccessfully($webhook);
}
$invoice = $subscription->user->findInvoice(
$webhook->subscription->transactions[0]->id
);
app(LocalInvoiceRepository::class)->createForUser(
$subscription->user, $invoice
);
$this->sendInvoiceNotification($subscription->user, $invoice);
}
/**
* Handle a successful invoice payment from a Braintree subscription.
*
* @param WebhookNotification $webhook
* @return Response
*/
protected function teamSubscriptionChargedSuccessfully($webhook)
{
$subscription = TeamSubscription::where(
'braintree_id', $webhook->subscription->id
)->first();
if (! $subscription || ! isset($webhook->subscription->transactions[0])) {
return;
}
$invoice = $subscription->team->findInvoice(
$webhook->subscription->transactions[0]->id
);
app(LocalInvoiceRepository::class)->createForTeam(
$subscription->team, $invoice
);
$this->sendInvoiceNotification($subscription->team, $invoice);
}
/**
* Handle a subscription cancellation notification from Braintree.
*
* @param string $subscriptionId
* @return Response
*/
protected function cancelSubscription($subscriptionId)
{
parent::cancelSubscription($subscriptionId);
if (! $this->getSubscriptionById($subscriptionId)) {
return $this->cancelTeamSubscription($subscriptionId);
}
if ($subscription = $this->getSubscriptionById($subscriptionId)) {
event(new SubscriptionCancelled($subscription->user));
}
return new Response('Webhook Handled', 200);
}
/**
* Handle a subscription cancellation notification from Braintree.
*
* @param string $subscriptionId
* @return Response
*/
protected function cancelTeamSubscription($subscriptionId)
{
$subscription = TeamSubscription::where(
'braintree_id', $subscriptionId
)->first();
if ($subscription && ! $subscription->cancelled()) {
$subscription->markAsCancelled();
event(new TeamSubscriptionCancelled($subscription->team));
}
return new Response('Webhook Handled', 200);
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Billing;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
class InvoiceController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Get all of the invoices for the current user.
*
* @param Request $request
* @return Response
*/
public function all(Request $request)
{
if (! $request->user()->hasBillingProvider()) {
return [];
}
return $request->user()->localInvoices;
}
/**
* Download the invoice with the given ID.
*
* @param Request $request
* @param string $id
* @return Response
*/
public function download(Request $request, $id)
{
$invoice = $request->user()->localInvoices()
->where('id', $id)->firstOrFail();
return $request->user()->downloadInvoice(
$invoice->provider_id, ['id' => $invoice->id] + Spark::invoiceDataFor($request->user())
);
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Billing;
use Laravel\Spark\Spark;
use Illuminate\Support\Facades\Mail;
trait SendsInvoiceNotifications
{
/**
* The invoice notification e-mail view.
*
* @var string
*/
protected $emailView = 'spark::settings.invoices.emails.invoice';
/**
* Send an invoice notification e-mail.
*
* @param mixed $billable
* @param \Laravel\Cashier\Invoice
* @return void
*/
protected function sendInvoiceNotification($billable, $invoice)
{
$invoiceData = Spark::invoiceDataFor($billable);
$data = compact('billable', 'invoice', 'invoiceData');
Mail::send($this->emailView, $data, function ($message) use ($billable, $invoice, $invoiceData) {
$this->buildInvoiceMessage($message, $billable, $invoice, $invoiceData);
});
}
/**
* Build the invoice notification message.
*
* @param \Illuminate\Mail\Message $message
* @param mixed $billable
* @param \Laravel\Cashier\Invoice
* @param array $invoiceData
* @return void
*/
protected function buildInvoiceMessage($message, $billable, $invoice, array $invoiceData)
{
$localInvoice = $billable->localInvoices()
->where('provider_id', $invoice->id)->firstOrFail();
$invoiceData['id'] = $localInvoice->id;
$message->to($billable->email, $billable->name)
->subject($invoiceData['product'].' Invoice')
->attachData($invoice->pdf($invoiceData), 'invoice.pdf');
}
}

View File

@@ -0,0 +1,121 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Billing;
use Laravel\Spark\Spark;
use Illuminate\Http\Response;
use Laravel\Cashier\Http\Controllers\WebhookController;
use Laravel\Spark\Events\Subscription\SubscriptionCancelled;
use Laravel\Spark\Contracts\Repositories\LocalInvoiceRepository;
use Laravel\Spark\Events\Teams\Subscription\SubscriptionCancelled as TeamSubscriptionCancelled;
class StripeWebhookController extends WebhookController
{
use SendsInvoiceNotifications;
/**
* Handle a successful invoice payment from a Stripe subscription.
*
* By default, this e-mails a copy of the invoice to the customer.
*
* @param array $payload
* @return Response
*/
protected function handleInvoicePaymentSucceeded(array $payload)
{
$user = $this->getUserByStripeId(
$payload['data']['object']['customer']
);
if (is_null($user)) {
return $this->teamInvoicePaymentSucceeded($payload);
}
$invoice = $user->findInvoice($payload['data']['object']['id']);
app(LocalInvoiceRepository::class)->createForUser($user, $invoice);
$this->sendInvoiceNotification(
$user, $invoice
);
return new Response('Webhook Handled', 200);
}
/**
* Handle a successful invoice payment from a Stripe subscription.
*
* @param array $payload
* @return Response
*/
protected function teamInvoicePaymentSucceeded(array $payload)
{
$team = Spark::team()->where(
'stripe_id', $payload['data']['object']['customer']
)->first();
if (is_null($team)) {
return;
}
$invoice = $team->findInvoice($payload['data']['object']['id']);
app(LocalInvoiceRepository::class)->createForTeam($team, $invoice);
$this->sendInvoiceNotification(
$team, $invoice
);
return new Response('Webhook Handled', 200);
}
/**
* Handle a cancelled customer from a Stripe subscription.
*
* @param array $payload
* @return Response
*/
protected function handleCustomerSubscriptionDeleted(array $payload)
{
parent::handleCustomerSubscriptionDeleted($payload);
$user = $this->getUserByStripeId($payload['data']['object']['customer']);
if (! $user) {
return $this->teamSubscriptionDeleted($payload);
}
event(new SubscriptionCancelled(
$this->getUserByStripeId($payload['data']['object']['customer']))
);
return new Response('Webhook Handled', 200);
}
/**
* Handle a cancelled customer from a Stripe subscription.
*
* @param array $payload
* @return Response
*/
protected function teamSubscriptionDeleted(array $payload)
{
$team = Spark::team()->where(
'stripe_id', $payload['data']['object']['customer']
)->first();
if ($team) {
$team->subscriptions->filter(function ($subscription) use ($payload) {
return $subscription->stripe_id === $payload['data']['object']['id'];
})->each(function ($subscription) {
$subscription->markAsCancelled();
});
} else {
return new Response('Webhook Handled', 200);
}
event(new TeamSubscriptionCancelled($team));
return new Response('Webhook Handled', 200);
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings;
use Laravel\Spark\Http\Controllers\Controller;
class DashboardController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the settings dashboard.
*
* @return Response
*/
public function show()
{
return view('spark::settings');
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\PaymentMethod;
use Laravel\Spark\Spark;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Interactions\Settings\PaymentMethod\UpdatePaymentMethod;
use Laravel\Spark\Contracts\Http\Requests\Settings\PaymentMethod\UpdatePaymentMethodRequest;
class PaymentMethodController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Update the payment method for the user.
*
* @param UpdatePaymentMethodRequest $request
* @return Response
*/
public function update(UpdatePaymentMethodRequest $request)
{
Spark::interact(UpdatePaymentMethod::class, [
$request->user(), $request->all(),
]);
}
}

View File

@@ -0,0 +1,58 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\PaymentMethod;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Repositories\CouponRepository;
use Laravel\Spark\Contracts\Interactions\Settings\PaymentMethod\RedeemCoupon;
class RedeemCouponController extends Controller
{
/**
* The coupon repository implementation.
*
* @var CouponRepository
*/
protected $coupons;
/**
* Create a new controller instance.
*
* @param \Laravel\Spark\Contracts\Repositories\CouponRepository $coupons
* @return void
*/
public function __construct(CouponRepository $coupons)
{
$this->coupons = $coupons;
$this->middleware('auth');
}
/**
* Redeem the given coupon code.
*
* @param Request $request
* @return Response
*/
public function redeem(Request $request)
{
$this->validate($request, [
'coupon' => 'required',
]);
// We will verify that the coupon can actually be redeemed. In some cases even
// valid coupons can not get redeemed by an existing user if this coupon is
// running as a promotion for brand new registrations to the application.
if (! $this->coupons->canBeRedeemed($request->coupon)) {
return response()->json(['coupon' => [
'This coupon code is invalid.'
]], 422);
}
Spark::interact(RedeemCoupon::class, [
$request->user(), $request->coupon
]);
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\PaymentMethod;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Repositories\UserRepository;
class VatIdController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Update the VAT ID for the user.
*
* @param Request $request
* @return Response
*/
public function update(Request $request)
{
$this->validate($request, [
'vat_id' => 'max:50|vat_id',
]);
Spark::call(UserRepository::class.'@updateVatId', [
$request->user(), $request->vat_id
]);
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Profile;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Interactions\Settings\Profile\UpdateContactInformation;
class ContactInformationController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Update the user's contact information settings.
*
* @param Request $request
* @return Response
*/
public function update(Request $request)
{
$this->interaction(
$request, UpdateContactInformation::class,
[$request->user(), $request->all()]
);
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Profile;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Interactions\Settings\Profile\UpdateProfilePhoto;
class PhotoController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Store the user's profile photo.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$this->interaction(
$request, UpdateProfilePhoto::class,
[$request->user(), $request->all()]
);
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Security;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Laravel\Spark\Http\Controllers\Controller;
class PasswordController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Update the user's password.
*
* @param Request $request
* @return Response
*/
public function update(Request $request)
{
$this->validate($request, [
'current_password' => 'required',
'password' => 'required|confirmed|min:'.Spark::minimumPasswordLength(),
]);
if (! Hash::check($request->current_password, $request->user()->password)) {
return response()->json([
'current_password' => ['The given password does not match our records.']
], 422);
}
$request->user()->forceFill([
'password' => bcrypt($request->password)
])->save();
}
}

View File

@@ -0,0 +1,81 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Security;
use Exception;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Laravel\Spark\Http\Requests\Settings\Security\EnableTwoFactorAuthRequest;
use Laravel\Spark\Contracts\Interactions\Settings\Security\EnableTwoFactorAuth;
use Laravel\Spark\Contracts\Interactions\Settings\Security\DisableTwoFactorAuth;
class TwoFactorAuthController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Enable two-factor authentication for the user.
*
* @param EnableTwoFactorAuthRequest $request
* @return Response
*/
public function enable(EnableTwoFactorAuthRequest $request)
{
try {
Spark::interact(EnableTwoFactorAuth::class, [
$request->user(), $request->country_code, $request->phone
]);
return $this->storeTwoFactorInformation($request);
} catch (Exception $e) {
app(ExceptionHandler::class)->report($e);
return response()->json(['phone' => [
'We were not able to enable two-factor authentication for this phone number.'
]], 422);
}
}
/**
* Store the two-factor authentication information on the user instance.
*
* @param EnableTwoFactorAuthRequest $request
* @return string
*/
protected function storeTwoFactorInformation($request)
{
$request->user()->forceFill([
'uses_two_factor_auth' => true,
'country_code' => $request->country_code,
'phone' => $request->phone,
'two_factor_reset_code' => bcrypt($code = str_random(40)),
])->save();
return $code;
}
/**
* Disable two-factor authentication for the user.
*
* @param Request $request
* @return Response
*/
public function disable(Request $request)
{
Spark::interact(DisableTwoFactorAuth::class, [$request->user()]);
$request->user()->forceFill([
'uses_two_factor_auth' => false,
])->save();
}
}

View File

@@ -0,0 +1,83 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Subscription;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Interactions\Subscribe;
use Laravel\Spark\Events\Subscription\SubscriptionUpdated;
use Laravel\Spark\Events\Subscription\SubscriptionCancelled;
use Laravel\Spark\Http\Requests\Settings\Subscription\UpdateSubscriptionRequest;
use Laravel\Spark\Contracts\Http\Requests\Settings\Subscription\CreateSubscriptionRequest;
class PlanController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Create the subscription for the user.
*
* @param CreateSubscriptionRequest $request
* @return Response
*/
public function store(CreateSubscriptionRequest $request)
{
$plan = Spark::plans()->where('id', $request->plan)->first();
Spark::interact(Subscribe::class, [
$request->user(), $plan, false, $request->all()
]);
}
/**
* Update the subscription for the user.
*
* @param \Laravel\Spark\Http\Requests\Settings\Subscription\UpdateSubscriptionRequest $request
* @return Response
*/
public function update(UpdateSubscriptionRequest $request)
{
$plan = Spark::plans()->where('id', $request->plan)->first();
// This method is used both for updating subscriptions and for resuming cancelled
// subscriptions that are still within their grace periods as this swap method
// will be used for either of these situations without causing any problems.
if ($plan->price === 0) {
return $this->destroy($request);
} else {
$subscription = $request->user()->subscription();
if (Spark::prorates()) {
$subscription->swap($request->plan);
} else {
$subscription->noProrate()->swap($request->plan);
}
}
event(new SubscriptionUpdated(
$request->user()->fresh()
));
}
/**
* Cancel the user's subscription.
*
* @param Request $request
* @return Response
*/
public function destroy(Request $request)
{
$request->user()->subscription()->cancel();
event(new SubscriptionCancelled($request->user()->fresh()));
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Teams\Billing;
use Laravel\Spark\Team;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
class BillingInformationController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Update the team's extra billing information.
*
* @param Request $request
* @param Team $team
* @return Response
*/
public function update(Request $request, Team $team)
{
abort_unless($request->user()->ownsTeam($team), 403);
$this->validate($request, [
'information' => 'max:2048',
]);
$team->forceFill([
'extra_billing_information' => $request->information,
])->save();
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Teams\Billing;
use Laravel\Spark\Team;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
class InvoiceController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Get all of the invoices for the given team.
*
* @param Request $request
* @param Team $team
* @return Response
*/
public function all(Request $request, Team $team)
{
abort_unless($request->user()->ownsTeam($team), 403);
if (! $team->hasBillingProvider()) {
return [];
}
return $team->localInvoices;
}
/**
* Download the invoice with the given ID.
*
* @param Request $request
* @param Team $team
* @param string $id
* @return Response
*/
public function download(Request $request, Team $team, $id)
{
abort_unless($request->user()->ownsTeam($team), 403);
$invoice = $team->localInvoices()
->where('id', $id)->firstOrFail();
return $team->downloadInvoice(
$invoice->provider_id, ['id' => $invoice->id] + Spark::invoiceDataFor($team)
);
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Teams;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
class DashboardController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the team settings dashboard.
*
* @param Request $request
* @param Team $team
* @return Response
*/
public function show(Request $request, $team)
{
abort_unless($request->user()->onTeam($team), 404);
return view('spark::settings.teams.team-settings', compact('team'));
}
}

View File

@@ -0,0 +1,74 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Teams;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Invitation;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Repositories\TeamRepository;
use Laravel\Spark\Http\Requests\Settings\Teams\CreateInvitationRequest;
use Laravel\Spark\Contracts\Interactions\Settings\Teams\SendInvitation;
class MailedInvitationController extends Controller
{
/**
* The team repository implementation.
*
* @var \Laravel\Spark\Contracts\Repositories\TeamRepository
*/
protected $teams;
/**
* Create a new controller instance.
*
* @param TeamRepository $teams
* @return void
*/
public function __construct(TeamRepository $teams)
{
$this->teams = $teams;
$this->middleware('auth');
}
/**
* Get all of the mailed invitations for the given team.
*
* @param Request $request
* @param \Laravel\Spark\Team $team
* @return Response
*/
public function all(Request $request, $team)
{
abort_unless($request->user()->onTeam($team), 404);
return $team->invitations;
}
/**
* Create a new invitation.
*
* @param CreateInvitationRequest $request
* @param \Laravel\Spark\Team $team
* @return Response
*/
public function store(CreateInvitationRequest $request, $team)
{
Spark::interact(SendInvitation::class, [$team, $request->email]);
}
/**
* Cancel / delete the given invitation.
*
* @param Request $request
* @param \Laravel\Spark\Invitation $invitation
* @return Response
*/
public function destroy(Request $request, Invitation $invitation)
{
abort_unless($request->user()->ownsTeam($invitation->team), 404);
$invitation->delete();
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Teams\PaymentMethod;
use Laravel\Spark\Team;
use Laravel\Spark\Spark;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Interactions\Settings\PaymentMethod\UpdatePaymentMethod;
use Laravel\Spark\Contracts\Http\Requests\Settings\PaymentMethod\UpdatePaymentMethodRequest;
class PaymentMethodController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Update the payment method for the user.
*
* @param UpdatePaymentMethodRequest $request
* @param Team $team
* @return Response
*/
public function update(UpdatePaymentMethodRequest $request, Team $team)
{
abort_unless($request->user()->ownsTeam($team), 403);
Spark::interact(UpdatePaymentMethod::class, [
$team, $request->all(),
]);
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Teams\PaymentMethod;
use Laravel\Spark\Team;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Repositories\CouponRepository;
use Laravel\Spark\Contracts\Interactions\Settings\PaymentMethod\RedeemCoupon;
class RedeemCouponController extends Controller
{
/**
* The coupon repository implementation.
*
* @var CouponRepository
*/
protected $coupons;
/**
* Create a new controller instance.
*
* @param \Laravel\Spark\Contracts\Repositories\CouponRepository $coupons
* @return void
*/
public function __construct(CouponRepository $coupons)
{
$this->coupons = $coupons;
$this->middleware('auth');
}
/**
* Redeem the given coupon code.
*
* @param Request $request
* @param Team $team
* @return Response
*/
public function redeem(Request $request, Team $team)
{
abort_unless($request->user()->ownsTeam($team), 403);
$this->validate($request, [
'coupon' => 'required',
]);
// We will verify that the coupon can actually be redeemed. In some cases even
// valid coupons can not get redeemed by an existing user if this coupon is
// running as a promotion for brand new registrations to the application.
if (! $this->coupons->canBeRedeemed($request->coupon)) {
return response()->json(['coupon' => [
'This coupon code is invalid.'
]], 422);
}
Spark::interact(RedeemCoupon::class, [
$team, $request->coupon
]);
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Teams\PaymentMethod;
use Laravel\Spark\Team;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Repositories\TeamRepository;
class VatIdController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Update the VAT ID for the team.
*
* @param Request $request
* @param Team $team
* @return Response
*/
public function update(Request $request, Team $team)
{
$this->validate($request, [
'vat_id' => 'max:50|vat_id',
]);
Spark::call(TeamRepository::class.'@updateVatId', [
$team, $request->vat_id
]);
}
}

View File

@@ -0,0 +1,65 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Teams;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Invitation;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Interactions\Settings\Teams\AddTeamMember;
class PendingInvitationController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Get all of the pending invitations for the user.
*
* @param Request $request
* @return Response
*/
public function all(Request $request)
{
return $request->user()->invitations()->with('team')->get();
}
/**
* Accept the given invitations.
*
* @param Request $request
* @param \Laravel\Spark\Invitation $invitation
* @return Response
*/
public function accept(Request $request, Invitation $invitation)
{
abort_unless($request->user()->id == $invitation->user_id, 404);
Spark::interact(AddTeamMember::class, [
$invitation->team, $request->user()
]);
$invitation->delete();
}
/**
* Reject the given invitations.
*
* @param Request $request
* @param \Laravel\Spark\Invitation $invitation
* @return Response
*/
public function reject(Request $request, Invitation $invitation)
{
abort_unless($request->user()->id == $invitation->user_id, 404);
$invitation->delete();
}
}

View File

@@ -0,0 +1,81 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Teams\Subscription;
use Laravel\Spark\Team;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Interactions\SubscribeTeam;
use Laravel\Spark\Events\Teams\Subscription\SubscriptionUpdated;
use Laravel\Spark\Events\Teams\Subscription\SubscriptionCancelled;
use Laravel\Spark\Http\Requests\Settings\Teams\Subscription\UpdateSubscriptionRequest;
use Laravel\Spark\Contracts\Http\Requests\Settings\Teams\Subscription\CreateSubscriptionRequest;
class PlanController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Create the subscription for the team.
*
* @param CreateSubscriptionRequest $request
* @param Team $team
* @return Response
*/
public function store(CreateSubscriptionRequest $request, Team $team)
{
Spark::interact(SubscribeTeam::class, [
$team, $request->plan(), false, $request->all()
]);
}
/**
* Update the subscription for the team.
*
* @param UpdateSubscriptionRequest $request
* @param Team $team
* @return Response
*/
public function update(UpdateSubscriptionRequest $request, Team $team)
{
$plan = $request->plan();
// This method is used both for updating subscriptions and for resuming cancelled
// subscriptions that are still within their grace periods as this swap method
// will be used for either of these situations without causing any problems.
if ($plan->price === 0) {
return $this->destroy($request, $team);
} else {
$team->subscription()->swap($request->plan);
}
event(new SubscriptionUpdated(
$team->fresh()
));
}
/**
* Cancel the team's subscription.
*
* @param Request $request
* @param Team $team
* @return Response
*/
public function destroy(Request $request, Team $team)
{
abort_unless($request->user()->ownsTeam($team), 403);
$team->subscription()->cancel();
event(new SubscriptionCancelled($team->fresh()));
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Teams;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Events\Teams\TeamDeleted;
use Laravel\Spark\Events\Teams\DeletingTeam;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Interactions\Settings\Teams\CreateTeam;
class TeamController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Create a new team.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
if (! Spark::createsAdditionalTeams()) {
abort(404);
}
$this->interaction($request, CreateTeam::class, [
$request->user(), $request->all()
]);
}
/**
* Delete the given team.
*
* @param Request $request
* @param \Laravel\Spark\Team $team
* @return Response
*/
public function destroy(Request $request, $team)
{
if (! $request->user()->ownsTeam($team)) {
abort(404);
}
event(new DeletingTeam($team));
$team->detachUsersAndDestroy();
event(new TeamDeleted($team));
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Teams;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Events\Teams\TeamMemberRemoved;
use Laravel\Spark\Http\Requests\Settings\Teams\RemoveTeamMemberRequest;
use Laravel\Spark\Contracts\Interactions\Settings\Teams\UpdateTeamMember;
class TeamMemberController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Update the given team member.
*
* @param Request $request
* @param \Laravel\Spark\Team $team
* @param mixed $member
* @return Response
*/
public function update(Request $request, $team, $member)
{
abort_unless($request->user()->ownsTeam($team), 404);
$this->interaction($request, UpdateTeamMember::class, [
$team, $member, $request->all()
]);
}
/**
* Remove the given team member from the team.
*
* @param RemoveTeamMemberRequest $request
* @param \Laravel\Spark\Team $team
* @param mixed $member
* @return Response
*/
public function destroy(RemoveTeamMemberRequest $request, $team, $member)
{
$team->users()->detach($member->id);
event(new TeamMemberRemoved($team, $member));
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Teams;
use Laravel\Spark\Spark;
use Laravel\Spark\Http\Controllers\Controller;
class TeamMemberRoleController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Get the available team member roles.
*
* @return Response
*/
public function all()
{
$roles = [];
foreach (Spark::roles() as $key => $value) {
$roles[] = ['value' => $key, 'text' => $value];
}
return response()->json($roles);
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Teams;
use Illuminate\Http\Request;
use Laravel\Spark\Http\Controllers\Controller;
class TeamNameController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Update the given team's name.
*
* @param Request $request
* @param \Laravel\Spark\Team $team
* @return Response
*/
public function update(Request $request, $team)
{
abort_unless($request->user()->ownsTeam($team), 404);
$this->validate($request, [
'name' => 'required|max:255',
]);
$team->forceFill([
'name' => $request->name,
])->save();
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace Laravel\Spark\Http\Controllers\Settings\Teams;
use Laravel\Spark\Http\Controllers\Controller;
use Laravel\Spark\Contracts\Interactions\Settings\Teams\UpdateTeamPhoto;
use Laravel\Spark\Http\Requests\Settings\Teams\UpdateTeamPhotoRequest;
class TeamPhotoController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Update the given team's photo.
*
* @param UpdateTeamPhotoRequest $request
* @param \Laravel\Spark\Team $team
* @return Response
*/
public function update(UpdateTeamPhotoRequest $request, $team)
{
$this->interaction(
$request, UpdateTeamPhoto::class,
[$team, $request->all()]
);
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace Laravel\Spark\Http\Controllers;
use Illuminate\Http\Request;
use Laravel\Spark\Contracts\Interactions\Support\SendSupportEmail;
class SupportController extends Controller
{
/**
* Send a customer support request e-mail.
*
* @param Request $request
* @return Response
*/
public function sendEmail(Request $request)
{
$this->interaction($request, SendSupportEmail::class, [
$request->all(),
]);
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Laravel\Spark\Http\Controllers;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
class TaxRateController extends Controller
{
/**
* Attempt to calculate the tax rate for the billing address.
*
* @param Request $request
* @return Response
*/
public function calculate(Request $request)
{
if (! $request->filled('city', 'state', 'zip', 'country')) {
return response()->json(['rate' => 0]);
}
$user = Spark::user();
$user->forceFill([
'vat_id' => $request->vat_id,
'billing_city' => $request->city,
'billing_state' => $request->state,
'billing_zip' => $request->zip,
'billing_country' => $request->country,
'card_country' => $request->country,
]);
return response()->json([
'rate' => $user->taxPercentage()
]);
}
}

View File

@@ -0,0 +1,86 @@
<?php
namespace Laravel\Spark\Http\Controllers;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Contracts\Repositories\TeamRepository;
class TeamController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Get all of the teams for the current user.
*
* @param Request $request
* @return Response
*/
public function all(Request $request)
{
return Spark::interact(
TeamRepository::class.'@forUser', [$request->user()]
);
}
/**
* Get the current team for the user.
*
* @param Request $request
* @return Response
*/
public function current(Request $request)
{
abort_unless($request->user()->current_team_id, 404);
return Spark::interact(TeamRepository::class.'@find', [
$request->user()->current_team_id
]);
}
/**
* Get the team matching the given ID.
*
* @param Request $request
* @param string $teamId
* @return Response
*/
public function show(Request $request, $teamId)
{
$team = Spark::interact(TeamRepository::class.'@find', [$teamId]);
abort_unless($request->user()->onTeam($team), 404);
if ($request->user()->ownsTeam($team)) {
$team->load('subscriptions');
$team->shouldHaveOwnerVisibility();
}
return $team;
}
/**
* Switch the current team the user is viewing.
*
* @param Request $request
* @param \Laravel\Spark\Team $team
* @return Response
*/
public function switchCurrentTeam(Request $request, $team)
{
abort_unless($request->user()->onTeam($team), 404);
$request->user()->switchToTeam($team);
return back();
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace Laravel\Spark\Http\Controllers;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Contracts\Repositories\CouponRepository;
class TeamCouponController extends Controller
{
/**
* The coupon repository implementation.
*
* @var \Laravel\Spark\Contracts\Repositories\CouponRepository
*/
protected $coupons;
/**
* Create a new controller instance.
*
* @param \Laravel\Spark\Contracts\Repositories\CouponRepository $coupons
* @return void
*/
public function __construct(CouponRepository $coupons)
{
$this->coupons = $coupons;
$this->middleware('auth')->only('current');
}
/**
* Get the current discount for the given team.
*
* @param Request $request
* @param string $teamId
* @return Response
*/
public function current(Request $request, $teamId)
{
$team = Spark::team()->where('id', $teamId)->firstOrFail();
if ($coupon = $this->coupons->forBillable($team)) {
return response()->json($coupon->toArray());
}
abort(204);
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace Laravel\Spark\Http\Controllers;
use Parsedown;
class TermsController extends Controller
{
/**
* Show the terms of service for the application.
*
* @return Response
*/
public function show()
{
return view('spark::terms', [
'terms' => (new Parsedown)->text(file_get_contents(base_path('terms.md')))
]);
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace Laravel\Spark\Http\Controllers;
use Illuminate\Http\Request;
use Laravel\Spark\Contracts\Repositories\TokenRepository;
class TokenController extends Controller
{
/**
* The token repository instance.
*
* @var TokenRepository
*/
protected $tokens;
/**
* Create a new controller instance.
*
* @param TokenRepository $tokens
* @return void
*/
public function __construct(TokenRepository $tokens)
{
$this->tokens = $tokens;
$this->middleware('auth');
}
/**
* Exchange the current transient API token for a new one.
*
* @param Request $request
* @return Response
*/
public function refresh(Request $request)
{
$this->tokens->deleteExpiredTokens($request->user());
return response('Refreshed.')->withCookie(
$this->tokens->createTokenCookie($request->user())
);
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace Laravel\Spark\Http\Controllers;
use Carbon\Carbon;
use Laravel\Spark\Spark;
use Illuminate\Http\Request;
use Laravel\Spark\Contracts\Repositories\UserRepository;
class UserController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth')->only(
'updateLastReadAnnouncementsTimestamp'
);
}
/**
* Get the current user of the application.
*
* @return Response
*/
public function current()
{
return Spark::interact(UserRepository::class.'@current');
}
/**
* Update the last read announcements timestamp.
*
* @param Request $request
* @return Response
*/
public function updateLastReadAnnouncementsTimestamp(Request $request)
{
$request->user()->forceFill([
'last_read_announcements_at' => Carbon::now(),
])->save();
}
}

View File

@@ -0,0 +1,103 @@
<?php
namespace Laravel\Spark\Http\Middleware;
use Closure;
use Laravel\Spark\Spark;
use Illuminate\Http\Response;
use Laravel\Spark\Contracts\Repositories\TokenRepository;
class CreateFreshApiToken
{
/**
* The token repository implementation.
*
* @var TokenRepository
*/
protected $tokens;
/**
* Create a new middleware instance.
*
* @param TokenRepository $tokens
* @return void
*/
public function __construct(TokenRepository $tokens)
{
$this->tokens = $tokens;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
$response = $next($request);
if ($this->shouldReceiveFreshToken($request, $response)) {
$response->withCookie($this->tokens->createTokenCookie($request->user()));
}
return $response;
}
/**
* Determine if the given request should receive a fresh token.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Http\Response $response
* @return bool
*/
protected function shouldReceiveFreshToken($request, $response)
{
return Spark::usesApi() && $this->requestShouldReceiveFreshToken($request) &&
$this->responseShouldReceiveFreshToken($response);
}
/**
* Determine if the request should receive a fresh token.
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
protected function requestShouldReceiveFreshToken($request)
{
return $request->isMethod('GET') && $request->user() && ! $request->ajax();
}
/**
* Determine if the response should receive a fresh token.
*
* @param \Illuminate\Http\Response $response
* @return bool
*/
protected function responseShouldReceiveFreshToken($response)
{
return $response instanceof Response &&
! $this->alreadyContainsToken($response);
}
/**
* Determine if the given response already contains a Spark API token.
*
* This avoids us overwriting a just "refreshed" token.
*
* @param \Illuminate\Http\Response $response
* @return bool
*/
protected function alreadyContainsToken($response)
{
foreach ($response->headers->getCookies() as $cookie) {
if ($cookie->getName() === 'spark_token') {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace Laravel\Spark\Http\Middleware;
use Laravel\Spark\Spark;
class VerifyTeamIsSubscribed
{
/**
* Verify the incoming request's current team has a subscription.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string $subscription
* @param string $plan
* @return \Illuminate\Http\Response
*/
public function handle($request, $next, $subscription = 'default', $plan = null)
{
if ($this->subscribed($request->user(), $subscription, $plan, func_num_args() === 2)) {
return $next($request);
}
return $request->ajax() || $request->wantsJson()
? response('Subscription Required.', 402)
: redirect('/settings/'.str_plural(Spark::teamString()).'/'.$request->user()->currentTeam->id.'#/subscription');
}
/**
* Determine if the given user's current team is subscribed to the given plan.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param string $subscription
* @param bool $plan
* @param bool $defaultSubscription
* @return bool
*/
protected function subscribed($user, $subscription, $plan, $defaultSubscription)
{
if (! $user || ! $user->currentTeam) {
return false;
}
return ($defaultSubscription && $user->currentTeam->onGenericTrial()) ||
$user->currentTeam->subscribed($subscription, $plan);
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace Laravel\Spark\Http\Middleware;
use Laravel\Spark\Spark;
class VerifyUserHasTeam
{
/**
* Verify the incoming request's user belongs to team.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return \Illuminate\Http\Response
*/
public function handle($request, $next)
{
if (Spark::usesTeams() && $request->user() && ! $request->user()->hasTeams()) {
return redirect('missing-'.Spark::teamString());
}
return $next($request);
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Laravel\Spark\Http\Middleware;
use Laravel\Spark\Spark;
class VerifyUserIsDeveloper
{
/**
* Determine if the authenticated user is a developer.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return \Illuminate\Http\Response
*/
public function handle($request, $next)
{
if ($request->user() && Spark::developer($request->user()->email)) {
return $next($request);
}
return $request->ajax() || $request->wantsJson()
? response('Unauthorized.', 401)
: redirect()->guest('login');
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace Laravel\Spark\Http\Middleware;
class VerifyUserIsSubscribed
{
/**
* Verify the incoming request's user has a subscription.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string $subscription
* @param string $plan
* @return \Illuminate\Http\Response
*/
public function handle($request, $next, $subscription = 'default', $plan = null)
{
if ($this->subscribed($request->user(), $subscription, $plan, func_num_args() === 2)) {
return $next($request);
}
return $request->ajax() || $request->wantsJson()
? response('Subscription Required.', 402)
: redirect('/settings#/subscription');
}
/**
* Determine if the given user is subscribed to the given plan.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param string $subscription
* @param string $plan
* @param bool $defaultSubscription
* @return bool
*/
protected function subscribed($user, $subscription, $plan, $defaultSubscription)
{
if (! $user) {
return false;
}
return ($defaultSubscription && $user->onGenericTrial()) ||
$user->subscribed($subscription, $plan);
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Laravel\Spark\Http\Requests\Auth;
use Laravel\Spark\Contracts\Http\Requests\Auth\RegisterRequest as Contract;
class BraintreeRegisterRequest extends RegisterRequest implements Contract
{
/**
* Get the validator for the request.
*
* @return \Illuminate\Validation\Validator
*/
public function validator()
{
return $this->registerValidator(['braintree_type', 'braintree_token']);
}
}

View File

@@ -0,0 +1,141 @@
<?php
namespace Laravel\Spark\Http\Requests\Auth;
use Laravel\Spark\Spark;
use Laravel\Spark\Invitation;
use Illuminate\Foundation\Http\FormRequest;
use Laravel\Spark\Contracts\Interactions\Auth\CreateUser;
use Laravel\Spark\Contracts\Repositories\CouponRepository;
class RegisterRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validator for a registration request.
*
* @param array $paymentAttributes
* @return \Illuminate\Validation\Validator
*/
protected function registerValidator(array $paymentAttributes)
{
$validator = $this->baseValidator();
// If a paid plan is selected, we will validate the given required fields which
// are typically the Stripe / Braintree tokens. If the selected plan is free
// of course we will not need to validate that these fields are available.
$validator->sometimes($paymentAttributes, 'required', function ($input) {
return $this->plan() && $this->plan()->price > 0;
});
return $this->after($validator);
}
/**
* Get the base validator instance for a register request.
*
* @return \Illuminate\Validation\Validator
*/
public function baseValidator()
{
$validator = Spark::interact(
CreateUser::class.'@validator', [$this]
);
$allPlanIdList = Spark::activePlanIdList().','.Spark::activeTeamPlanIdList();
$validator->sometimes('plan', 'required|in:'.$allPlanIdList, function () {
return Spark::needsCardUpFront();
});
return $validator;
}
/**
* Setup the "after" callabck for the validator.
*
* @param \Illuminate\Validation\Validator $validator
* @return \Illuminate\Validation\Validator
*/
protected function after($validator)
{
return $validator->after(function ($validator) {
if ($this->coupon) {
$this->validateCoupon($validator);
}
if ($this->invitation) {
$this->validateInvitation($validator);
}
});
}
/**
* Validate the coupon on the request.
*
* @param \Illuminate\Validation\Validator $validator
* @return void
*/
protected function validateCoupon($validator)
{
if (! app(CouponRepository::class)->valid($this->coupon)) {
$validator->errors()->add('coupon', 'This coupon code is invalid.');
}
}
/**
* Validate the invitation code on the request.
*
* @param \Illuminate\Validation\Validator $validator
* @return void
*/
protected function validateInvitation($validator)
{
if (! $this->invitation()) {
$validator->errors()->add('invitation', 'This invitation code is invalid.');
}
}
/**
* Determine if the request contains a paid plan.
*
* @return bool
*/
public function hasPaidPlan()
{
return $this->plan() && $this->plan()->price > 0;
}
/**
* Get the full plan array for the specified plan.
*
* @return \Laravel\Spark\Plan|null
*/
public function plan()
{
if ($this->plan) {
return Spark::plans()->merge(Spark::teamPlans())->where('id', $this->plan)->first();
}
}
/**
* Get the full invitation instance.
*
* @return \Laravel\Spark\Invitation
*/
public function invitation()
{
if ($this->invitation) {
return Invitation::where('token', $this->invitation)->first();
}
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Laravel\Spark\Http\Requests\Auth;
use Laravel\Spark\Spark;
use Laravel\Spark\Http\Requests\ValidatesBillingAddresses;
use Laravel\Spark\Contracts\Http\Requests\Auth\RegisterRequest as Contract;
class StripeRegisterRequest extends RegisterRequest implements Contract
{
use ValidatesBillingAddresses;
/**
* Get the validator for the request.
*
* @return \Illuminate\Validation\Validator
*/
public function validator()
{
$validator = $this->registerValidator(['stripe_token']);
if (Spark::collectsBillingAddress() && $this->hasPaidPlan()) {
$this->validateBillingAddress($validator);
}
return $validator;
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\API;
class CreateTokenRequest extends TokenRequest
{
//
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\API;
use Laravel\Spark\Spark;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Http\FormRequest;
class TokenRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validator for the request.
*
* @return \Illuminate\Validation\Validator
*/
public function validator()
{
return $this->validateAbilities(Validator::make($this->all(), [
'name' => 'required|max:255',
], $this->messages()));
}
/**
* Configure the valdiator to validate the token abilities.
*
* @param \Illuminate\Validation\Validator $validator
* @return \Illuminate\Validation\Validator
*/
protected function validateAbilities($validator)
{
$abilities = implode(',', array_keys(Spark::tokensCan()));
$validator->sometimes('abilities', 'required|array|in:'.$abilities, function () {
return count(Spark::tokensCan()) > 0;
});
return $validator;
}
/**
* Set custom messages for validator errors.
*
* @return array
*/
public function messages()
{
return [
'abilities.required' => 'Please select at least one ability.',
];
}
}

View File

@@ -0,0 +1,8 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\API;
class UpdateTokenRequest extends TokenRequest
{
//
}

View File

@@ -0,0 +1,32 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\PaymentMethod;
use Illuminate\Foundation\Http\FormRequest;
use Laravel\Spark\Contracts\Http\Requests\Settings\PaymentMethod\UpdatePaymentMethodRequest;
class UpdateBraintreePaymentMethodRequest extends FormRequest implements UpdatePaymentMethodRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'braintree_type' => 'required',
'braintree_token' => 'required',
];
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\PaymentMethod;
use Laravel\Spark\Spark;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Laravel\Spark\Http\Requests\ValidatesBillingAddresses;
use Laravel\Spark\Contracts\Http\Requests\Settings\PaymentMethod\UpdatePaymentMethodRequest;
class UpdateStripePaymentMethodRequest extends FormRequest implements UpdatePaymentMethodRequest
{
use ValidatesBillingAddresses;
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validator for the request.
*
* @return \Illuminate\Validation\Validator
*/
public function validator()
{
$validator = Validator::make($this->all(), [
'stripe_token' => 'required',
]);
if (Spark::collectsBillingAddress()) {
$this->validateBillingAddress($validator);
}
return $validator;
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\Security;
use Illuminate\Foundation\Http\FormRequest;
class EnableTwoFactorAuthRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'country_code' => 'required|numeric',
'phone' => 'required|numeric',
];
}
/**
* Get data to be validated from the request.
*
* @return array
*/
protected function validationData()
{
if ($this->phone) {
$this->merge(['phone' => preg_replace('/[^0-9]/', '', $this->phone)]);
}
return $this->all();
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\Subscription;
use Laravel\Spark\Spark;
use Illuminate\Support\Facades\Validator;
use Laravel\Spark\Contracts\Http\Requests\Settings\Subscription\CreateSubscriptionRequest as Contract;
class CreateBraintreeSubscriptionRequest extends CreateSubscriptionRequest implements Contract
{
/**
* Get the validator for the request.
*
* @return \Illuminate\Validation\Validator
*/
public function validator()
{
$validator = Validator::make($this->all(), [
'braintree_type' => 'required',
'braintree_token' => 'required',
'plan' => 'required|in:'.Spark::activePlanIdList()
]);
return $validator->after(function ($validator) {
$this->validatePlanEligibility($validator);
if ($this->coupon) {
$this->validateCoupon($validator);
}
});
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\Subscription;
use Laravel\Spark\Spark;
use Illuminate\Support\Facades\Validator;
use Laravel\Spark\Http\Requests\ValidatesBillingAddresses;
use Laravel\Spark\Contracts\Http\Requests\Settings\Subscription\CreateSubscriptionRequest as Contract;
class CreateStripeSubscriptionRequest extends CreateSubscriptionRequest implements Contract
{
use ValidatesBillingAddresses;
/**
* Get the validator for the request.
*
* @return \Illuminate\Validation\Validator
*/
public function validator()
{
$validator = Validator::make($this->all(), [
'stripe_token' => 'required',
'plan' => 'required|in:'.Spark::activePlanIdList(),
'vat_id' => 'nullable|max:50|vat_id',
]);
if (Spark::collectsBillingAddress()) {
$this->validateBillingAddress($validator);
}
return $validator->after(function ($validator) {
$this->validatePlanEligibility($validator);
if ($this->coupon) {
$this->validateCoupon($validator);
}
});
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\Subscription;
use Illuminate\Foundation\Http\FormRequest;
use Laravel\Spark\Contracts\Repositories\CouponRepository;
class CreateSubscriptionRequest extends FormRequest
{
use DeterminesPlanEligibility;
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Validate the coupon on the request.
*
* @param \Illuminate\Validation\Validator $validator
* @return void
*/
protected function validateCoupon($validator)
{
if (! app(CouponRepository::class)->valid($this->coupon)) {
$validator->errors()->add('coupon', 'This coupon code is invalid.');
}
}
}

View File

@@ -0,0 +1,113 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\Subscription;
use Laravel\Spark\Spark;
use Laravel\Spark\Exceptions\IneligibleForPlan;
trait DeterminesPlanEligibility
{
/**
* Validate that the plan is eligible based on team restrictions.
*
* @param \Illuminate\Validation\Validator $validator
* @return void
*/
protected function validatePlanEligibility($validator)
{
$plan = Spark::plans()->where('id', $this->plan)->first();
// If the desired plan is free, we will always need to let the user switch to that
// plan since we'll want the user to always be able to cancel this subscription
// without preventing them. So, we will just return here if it's a free plan.
if (! $plan || $plan->price === 0) {
return;
}
$this->callCustomCallback($validator, $plan);
// If the user is ineligible for a plan based on their team member or collaborator
// count, we will prevent them switching to this plan and send an error message
// back to the client informing them of this limitation and they can upgrade.
if (! $this->userIsEligibleForPlan($plan)) {
$validator->errors()->add(
'plan', trans('spark::validation.eligibility')
);
}
}
/**
* Determine if the user is eligible to move to a given plan.
*
* @param \Laravel\Spark\Plan $plan
* @return bool
*/
protected function userIsEligibleForPlan($plan)
{
return ! $this->exceedsMaximumTeams($plan) &&
! $this->exceedsMaximumTeamMembers($plan) &&
! $this->exceedsMaximumCollaborators($plan);
}
/**
* Determine if the user exceeds the maximum teams.
*
* @param \Laravel\Spark\Plan $plan
* @return bool
*/
protected function exceedsMaximumTeams($plan)
{
if (is_null($plan->teams)) {
return false;
}
return $plan->teams < $this->user()->ownedTeams()->count();
}
/**
* Determine if the user exceeds the maximum team members for the plan.
*
* @param \Laravel\Spark\Plan $plan
* @return bool
*/
protected function exceedsMaximumTeamMembers($plan)
{
if (is_null($plan->teamMembers)) {
return false;
}
return ! is_null($this->user()->teams->first(function ($team) use ($plan) {
return $plan->teamMembers < $team->totalPotentialUsers();
}));
}
/**
* Determine if the user exceeds the maximum total collaborators for the plan.
*
* @param \Laravel\Spark\Plan $plan
* @return bool
*/
protected function exceedsMaximumCollaborators($plan)
{
return ! is_null($plan->collaborators) &&
$plan->collaborators < $this->user()->totalPotentialCollaborators();
}
/**
* Call the custom plan eligibility checker callback.
*
* @param \Illuminate\Validation\Validator $validator
* @param \Laravel\Spark\Plan $plan
* @return void
*/
protected function callCustomCallback($validator, $plan)
{
try {
if (! Spark::eligibleForPlan($this->user(), $plan)) {
$validator->errors()->add('plan', 'You are not eligible for this plan.');
}
} catch (IneligibleForPlan $e) {
$validator->errors()->add('plan', $e->getMessage());
}
}
}

View File

@@ -0,0 +1,38 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\Subscription;
use Laravel\Spark\Spark;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Http\FormRequest;
class UpdateSubscriptionRequest extends FormRequest
{
use DeterminesPlanEligibility;
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validator for the request.
*
* @return \Illuminate\Validation\Validator
*/
public function validator()
{
$validator = Validator::make($this->all(), [
'plan' => 'required|in:'.Spark::activePlanIdList()
]);
return $validator->after(function ($validator) {
$this->validatePlanEligibility($validator);
});
}
}

View File

@@ -0,0 +1,131 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\Teams;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Http\FormRequest;
class CreateInvitationRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return $this->user()->ownsTeam($this->team);
}
/**
* Get the validator for the request.
*
* @return \Illuminate\Validation\Validator
*/
public function validator()
{
$validator = Validator::make($this->all(), [
'email' => 'required|email|max:255',
]);
$validator->after(function ($validator) {
$this->validateMaxTeamMembersNotExceeded($validator);
});
return $validator->after(function ($validator) {
return $this->verifyEmailNotAlreadyOnTeam($validator, $this->team)
->verifyEmailNotAlreadyInvited($validator, $this->team);
});
}
/**
* Verify that the maximum number of team members hasn't been exceeded.
*
* @param \Illuminate\Validation\Validator $validator
* @return void
*/
protected function validateMaxTeamMembersNotExceeded($validator)
{
if ($plan = $this->user()->sparkPlan()) {
$this->validateMaxTeamMembersNotExceededForPlan($validator, $plan);
}
if ($plan = $this->team->sparkPlan()) {
$this->validateMaxTeamMembersNotExceededForPlan($validator, $plan);
}
}
/**
* Verify the team member limit hasn't been exceeded for the given plan.
*
* @param \Illuminate\Validation\Validator $validator
* @param \Laravel\Spark\Plan $plan
* @return void
*/
protected function validateMaxTeamMembersNotExceededForPlan($validator, $plan)
{
if (is_null($plan->teamMembers) && is_null($plan->collaborators)) {
return;
}
if ($this->exceedsMaxTeamMembers($plan) || $this->exceedsMaxCollaborators($plan)) {
$validator->errors()->add('email', 'Please upgrade your subscription to add more team members.');
}
}
/**
* Determine if the request will exceed the max allowed team members.
*
* @param \Laravel\Spark\Plan $plan
* @return bool
*/
protected function exceedsMaxTeamMembers($plan)
{
return ! is_null($plan->teamMembers) &&
$plan->teamMembers <= $this->team->totalPotentialUsers();
}
/**
* Determine if the request will exceed the max allowed collaborators.
*
* @param \Laravel\Spark\Plan $plan
* @return bool
*/
protected function exceedsMaxCollaborators($plan)
{
return ! is_null($plan->collaborators) &&
$plan->collaborators <= $this->user()->totalPotentialCollaborators();
}
/**
* Verify that the given e-mail is not already on the team.
*
* @param \Illuminate\Validation\Validator $validator
* @param \Laravel\Spark\Team $team
* @return $this
*/
protected function verifyEmailNotAlreadyOnTeam($validator, $team)
{
if ($team->users()->where('email', $this->email)->exists()) {
$validator->errors()->add('email', 'That user is already on the team.');
}
return $this;
}
/**
* Verify that the given e-mail is not already invited.
*
* @param \Illuminate\Validation\Validator $validator
* @param \Laravel\Spark\Team $team
* @return $this
*/
protected function verifyEmailNotAlreadyInvited($validator, $team)
{
if ($team->invitations()->where('email', $this->email)->exists()) {
$validator->errors()->add('email', 'That user is already invited to the team.');
}
return $this;
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\Teams;
use Illuminate\Foundation\Http\FormRequest;
class RemoveTeamMemberRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
$team = $this->route('team');
$member = $this->route('team_member');
return ($this->user()->ownsTeam($team) && $this->user()->id !== $member->id) ||
(! $this->user()->ownsTeam($team) && $this->user()->id === $member->id);
}
/**
* Get the validation rules for the request.
*
* @return array
*/
public function rules()
{
return [];
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\Teams\Subscription;
use Laravel\Spark\Contracts\Http\Requests\Settings\Teams\Subscription\CreateSubscriptionRequest as Contract;
class CreateBraintreeSubscriptionRequest extends CreateSubscriptionRequest implements Contract
{
/**
* Get the validator for the request.
*
* @return \Illuminate\Validation\Validator
*/
public function validator()
{
return $this->baseValidator([
'braintree_type' => 'required',
'braintree_token' => 'required',
]);
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\Teams\Subscription;
use Laravel\Spark\Spark;
use Laravel\Spark\Http\Requests\ValidatesBillingAddresses;
use Laravel\Spark\Contracts\Http\Requests\Settings\Teams\Subscription\CreateSubscriptionRequest as Contract;
class CreateStripeSubscriptionRequest extends CreateSubscriptionRequest implements Contract
{
use ValidatesBillingAddresses;
/**
* Get the validator for the request.
*
* @return \Illuminate\Validation\Validator
*/
public function validator()
{
$validator = $this->baseValidator([
'stripe_token' => 'required',
'vat_id' => 'nullable|max:50|vat_id',
]);
if (Spark::collectsBillingAddress()) {
$this->validateBillingAddress($validator);
}
return $validator;
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\Teams\Subscription;
use Laravel\Spark\Spark;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Laravel\Spark\Contracts\Repositories\CouponRepository;
class CreateSubscriptionRequest extends FormRequest
{
use DeterminesTeamPlanEligibility;
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return $this->user() && $this->user()->ownsTeam($this->route('team'));
}
/**
* Get the validator instance for the request.
*
* @param array $rules
* @return \Illuminate\Validation\Validator
*/
public function baseValidator(array $rules)
{
$validator = Validator::make($this->all(), array_merge([
'plan' => 'required|in:'.Spark::activeTeamPlanIdList()
], $rules));
return $validator->after(function ($validator) {
$this->validatePlanEligibility($validator);
if ($this->coupon) {
$this->validateCoupon($validator);
}
});
}
/**
* Validate the coupon on the request.
*
* @param \Illuminate\Validation\Validator $validator
* @return void
*/
protected function validateCoupon($validator)
{
if (! app(CouponRepository::class)->valid($this->coupon)) {
$validator->errors()->add('coupon', 'This coupon code is invalid.');
}
}
/**
* Get the Spark plan associated with the request.
*
* @return \Laravel\Spark\Plan
*/
public function plan()
{
return Spark::teamPlans()->where('id', $this->plan)->first();
}
}

View File

@@ -0,0 +1,81 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\Teams\Subscription;
use Laravel\Spark\Spark;
use Laravel\Spark\Exceptions\IneligibleForPlan;
trait DeterminesTeamPlanEligibility
{
/**
* Validate that the plan is eligible based on team restrictions.
*
* @param \Illuminate\Validation\Validator $validator
* @return void
*/
protected function validatePlanEligibility($validator)
{
$plan = Spark::teamPlans()->where('id', $this->plan)->first();
// If the desired plan is free, we will always need to let the user switch to that
// plan since we'll want the user to always be able to cancel this subscription
// without preventing them. So, we will just return here if it's a free plan.
if (! $plan || $plan->price === 0) {
return;
}
$this->callCustomCallback($validator, $plan);
// If the user is ineligible for a plan based on their team member or collaborator
// count, we will prevent them switching to this plan and send an error message
// back to the client informing them of this limitation and they can upgrade.
if (! $this->teamIsEligibleForPlan($this->route('team'), $plan)) {
$validator->errors()->add(
'plan', 'This team has too many team members for the selected plan.'
);
}
}
/**
* Determine if the team is eligible to move to a given plan.
*
* @param \Laravel\Spark\Team $team
* @param \Laravel\Spark\Plan $plan
* @return bool
*/
protected function teamIsEligibleForPlan($team, $plan)
{
return ! $this->exceedsMaximumTeamMembers($team, $plan);
}
/**
* Determine if the team exceeds the maximum team members for the plan.
*
* @param \Laravel\Spark\Team $team
* @param \Laravel\Spark\Plan $plan
* @return bool
*/
protected function exceedsMaximumTeamMembers($team, $plan)
{
return ! is_null($plan->teamMembers)
? $plan->teamMembers < $team->totalPotentialUsers() : false;
}
/**
* Call the custom plan eligibility checker callback.
*
* @param \Illuminate\Validation\Validator $validator
* @param \Laravel\Spark\Plan $plan
* @return void
*/
protected function callCustomCallback($validator, $plan)
{
try {
if (! Spark::eligibleForTeamPlan($this->route('team'), $plan)) {
$validator->errors()->add('plan', 'This team is not eligible for this plan.');
}
} catch (IneligibleForPlan $e) {
$validator->errors()->add('plan', $e->getMessage());
}
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\Teams\Subscription;
use Laravel\Spark\Spark;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Http\FormRequest;
class UpdateSubscriptionRequest extends FormRequest
{
use DeterminesTeamPlanEligibility;
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return $this->user()->ownsTeam($this->route('team'));
}
/**
* Get the validator for the request.
*
* @return \Illuminate\Validation\Validator
*/
public function validator()
{
$validator = Validator::make($this->all(), [
'plan' => 'required|in:'.Spark::activeTeamPlanIdList()
]);
return $validator->after(function ($validator) {
$this->validatePlanEligibility($validator);
});
}
/**
* Get the Spark plan associated with the request.
*
* @return \Laravel\Spark\Plan
*/
public function plan()
{
return Spark::teamPlans()->where('id', $this->plan)->first();
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Laravel\Spark\Http\Requests\Settings\Teams;
use Illuminate\Foundation\Http\FormRequest;
class UpdateTeamPhotoRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return $this->user()->ownsTeam($this->route('team'));
}
/**
* Get the validation rules for the request.
*
* @return array
*/
public function rules()
{
return [
'photo' => 'required|image|max:4000'
];
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace Laravel\Spark\Http\Requests;
use Laravel\Spark\Services\Stripe as StripeService;
trait ValidatesBillingAddresses
{
/**
* Merges billing address validation rules into the given validator.
*
* @param \Illuminate\Validation\Validator $validator
* @return void
*/
protected function validateBillingAddress($validator)
{
$this->mergeCardCountryIntoRequest();
$validator->addRules([
'address' => 'required|max:255',
'address_line_2' => 'max:255',
'city' => 'required|max:255',
'state' => 'required|max:255|state:'.$this->country,
'zip' => 'required|max:25',
'country' => 'required|max:2|country',
]);
$validator->after(function ($validator) {
$this->validateLocation($validator);
});
}
/**
* Merge the billing card country into the request.
*
* @return void
*/
protected function mergeCardCountryIntoRequest()
{
if (! $this->stripe_token) {
return;
}
$this->merge(['card_country' => app(StripeService::class)->countryForToken(
$this->stripe_token
)]);
}
/**
* Validate that the request's location information agrees.
*
* @param \Illuminate\Validation\Validator $validator
* @return void
*/
protected function validateLocation($validator)
{
if (! app(StripeService::class)->tokenIsForCountry($this->stripe_token, $this->country)) {
$validator->errors()->add(
'country', 'This country does not match the origin country of your card.'
);
}
}
}

197
spark/src/Http/routes.php Normal file
View File

@@ -0,0 +1,197 @@
<?php
$router->group(['middleware' => 'web'], function ($router) {
$teamString = Spark::teamString();
$pluralTeamString = str_plural(Spark::teamString());
// Terms Of Service...
$router->get('/terms', 'TermsController@show')->name('terms');
// Missing Team Notice...
$router->get('/missing-'.$teamString, 'MissingTeamController@show');
// Customer Support...
$router->post('/support/email', 'SupportController@sendEmail');
// API Token Refresh...
$router->put('/spark/token', 'TokenController@refresh');
// Users...
$router->get('/user/current', 'UserController@current');
$router->put('/user/last-read-announcements-at', 'UserController@updateLastReadAnnouncementsTimestamp');
// Notifications
$router->get('/notifications/recent', 'NotificationController@recent');
$router->put('/notifications/read', 'NotificationController@markAsRead');
// Settings Dashboard...
$router->get('/settings', 'Settings\DashboardController@show')->name('settings');
// Profile Contact Information...
$router->put('/settings/contact', 'Settings\Profile\ContactInformationController@update');
// Profile Photo...
$router->post('/settings/photo', 'Settings\Profile\PhotoController@store');
// Teams...
if (Spark::usesTeams()) {
// General Settings...
$router->get('/settings/'.$pluralTeamString.'/roles', 'Settings\Teams\TeamMemberRoleController@all');
$router->get('/settings/'.$pluralTeamString.'/{team}', 'Settings\Teams\DashboardController@show')->name('settings.team');
$router->get('/'.$pluralTeamString.'', 'TeamController@all');
$router->get('/'.$pluralTeamString.'/current', 'TeamController@current');
$router->get('/'.$pluralTeamString.'/{team_id}', 'TeamController@show');
$router->post('/settings/'.$pluralTeamString, 'Settings\Teams\TeamController@store');
$router->post('/settings/'.$pluralTeamString.'/{team}/photo', 'Settings\Teams\TeamPhotoController@update');
$router->put('/settings/'.$pluralTeamString.'/{team}/name', 'Settings\Teams\TeamNameController@update');
// Invitations...
$router->get('/settings/'.$pluralTeamString.'/{team}/invitations', 'Settings\Teams\MailedInvitationController@all');
$router->post('/settings/'.$pluralTeamString.'/{team}/invitations', 'Settings\Teams\MailedInvitationController@store');
$router->get('/settings/invitations/pending', 'Settings\Teams\PendingInvitationController@all');
$router->get('/invitations/{invitation}', 'InvitationController@show');
$router->post('/settings/invitations/{invitation}/accept', 'Settings\Teams\PendingInvitationController@accept');
$router->post('/settings/invitations/{invitation}/reject', 'Settings\Teams\PendingInvitationController@reject');
$router->delete('/settings/invitations/{invitation}', 'Settings\Teams\MailedInvitationController@destroy');
$router->put('/settings/'.$pluralTeamString.'/{team}/members/{team_member}', 'Settings\Teams\TeamMemberController@update');
$router->delete('/settings/'.$pluralTeamString.'/{team}/members/{team_member}', 'Settings\Teams\TeamMemberController@destroy');
$router->delete('/settings/'.$pluralTeamString.'/{team}', 'Settings\Teams\TeamController@destroy');
$router->get('/'.$pluralTeamString.'/{team}/switch', 'TeamController@switchCurrentTeam');
// Billing
// Subscription Settings...
$router->post('/settings/'.$pluralTeamString.'/{team}/subscription', 'Settings\Teams\Subscription\PlanController@store');
$router->put('/settings/'.$pluralTeamString.'/{team}/subscription', 'Settings\Teams\Subscription\PlanController@update');
$router->delete('/settings/'.$pluralTeamString.'/{team}/subscription', 'Settings\Teams\Subscription\PlanController@destroy');
// VAT ID Settings...
$router->put('/settings/'.$pluralTeamString.'/{team}/payment-method/vat-id', 'Settings\Teams\PaymentMethod\VatIdController@update');
// Credit Card Settings...
$router->put('/settings/'.$pluralTeamString.'/{team}/payment-method', 'Settings\Teams\PaymentMethod\PaymentMethodController@update');
// Redeem Coupon...
$router->post('/settings/'.$pluralTeamString.'/{team}/payment-method/coupon', 'Settings\Teams\PaymentMethod\RedeemCouponController@redeem');
// Billing History...
$router->put(
'/settings/'.$pluralTeamString.'/{team}/extra-billing-information',
'Settings\Teams\Billing\BillingInformationController@update'
);
// Coupons...
$router->get('/coupon/'.$teamString.'/{id}', 'TeamCouponController@current');
// Invoices...
$router->get('/settings/'.$pluralTeamString.'/{team}/invoices', 'Settings\Teams\Billing\InvoiceController@all');
$router->get('/settings/'.$pluralTeamString.'/{team}/invoice/{id}', 'Settings\Teams\Billing\InvoiceController@download');
}
// Security Settings...
$router->put('/settings/password', 'Settings\Security\PasswordController@update');
$router->post('/settings/two-factor-auth', 'Settings\Security\TwoFactorAuthController@enable');
$router->delete('/settings/two-factor-auth', 'Settings\Security\TwoFactorAuthController@disable');
// API Settings
$router->get('/settings/api/tokens', 'Settings\API\TokenController@all');
$router->post('/settings/api/token', 'Settings\API\TokenController@store');
$router->put('/settings/api/token/{token_id}', 'Settings\API\TokenController@update');
$router->get('/settings/api/token/abilities', 'Settings\API\TokenAbilitiesController@all');
$router->delete('/settings/api/token/{token_id}', 'Settings\API\TokenController@destroy');
// Plans...
$router->get('/spark/plans', 'PlanController@all');
// Subscription Settings...
$router->post('/settings/subscription', 'Settings\Subscription\PlanController@store');
$router->put('/settings/subscription', 'Settings\Subscription\PlanController@update');
$router->delete('/settings/subscription', 'Settings\Subscription\PlanController@destroy');
// VAT ID Settings...
$router->put('/settings/payment-method/vat-id', 'Settings\PaymentMethod\VatIdController@update');
// Credit Card Settings...
$router->put('/settings/payment-method', 'Settings\PaymentMethod\PaymentMethodController@update');
// Redeem Coupon...
$router->post('/settings/payment-method/coupon', 'Settings\PaymentMethod\RedeemCouponController@redeem');
// Billing History...
$router->put(
'/settings/extra-billing-information',
'Settings\Billing\BillingInformationController@update'
);
// Invoices...
$router->get('/settings/invoices', 'Settings\Billing\InvoiceController@all');
$router->get('/settings/invoice/{id}', 'Settings\Billing\InvoiceController@download');
// Coupons...
$router->get('/coupon/user/{id}', 'CouponController@current');
$router->get('/coupon/{code}', 'CouponController@show');
// Kiosk...
$router->get('/spark/kiosk', 'Kiosk\DashboardController@show')->name('kiosk');
// Kiosk Search...
$router->post('/spark/kiosk/users/search', 'Kiosk\SearchController@performBasicSearch');
// Kiosk Announcements...
$router->get('/spark/kiosk/announcements', 'Kiosk\AnnouncementController@all');
$router->post('/spark/kiosk/announcements', 'Kiosk\AnnouncementController@store');
$router->put('/spark/kiosk/announcements/{id}', 'Kiosk\AnnouncementController@update');
$router->delete('/spark/kiosk/announcements/{id}', 'Kiosk\AnnouncementController@destroy');
// Kiosk Metrics / Performance Indicators...
$router->get('/spark/kiosk/performance-indicators', 'Kiosk\PerformanceIndicatorsController@all');
$router->get('/spark/kiosk/performance-indicators/revenue', 'Kiosk\PerformanceIndicatorsController@revenue');
$router->get('/spark/kiosk/performance-indicators/plans', 'Kiosk\PerformanceIndicatorsController@subscribers');
$router->get('/spark/kiosk/performance-indicators/trialing', 'Kiosk\PerformanceIndicatorsController@trials');
// Kiosk User Profiles...
$router->get('/spark/kiosk/users/{id}/profile', 'Kiosk\ProfileController@show');
// Kiosk Discounts...
$router->post('/spark/kiosk/users/discount/{id}', 'Kiosk\DiscountController@store');
// Kiosk Impersonation...
$router->get('/spark/kiosk/users/impersonate/{id}', 'Kiosk\ImpersonationController@impersonate');
$router->get('/spark/kiosk/users/stop-impersonating', 'Kiosk\ImpersonationController@stopImpersonating');
// Authentication...
$router->get('/login', 'Auth\LoginController@showLoginForm')->name('login');
$router->post('/login', 'Auth\LoginController@login');
$router->get('/logout', 'Auth\LoginController@logout')->name('logout');
// Two-Factor Authentication Routes...
$router->get('/login/token', 'Auth\LoginController@showTokenForm');
$router->post('/login/token', 'Auth\LoginController@verifyToken');
// Two-Factor Emergency Token Login Routes...
$router->get('/login-via-emergency-token', 'Auth\EmergencyLoginController@showLoginForm');
$router->post('/login-via-emergency-token', 'Auth\EmergencyLoginController@login');
// Registration...
$router->get('/register', 'Auth\RegisterController@showRegistrationForm')->name('register');
$router->post('/register', 'Auth\RegisterController@register');
// Password Reset...
$router->get('/password/reset/{token?}', 'Auth\PasswordController@showResetForm')->name('password.reset');
$router->post('/password/email', 'Auth\PasswordController@sendResetLinkEmail');
$router->post('/password/reset', 'Auth\PasswordController@reset');
});
// Tax Rates...
$router->post('/tax-rate', 'TaxRateController@calculate');
// Geocoding...
$router->get('/geocode/country', 'GeocodingController@country');
$router->get('/geocode/states/{country}', 'GeocodingController@states');
// Webhooks...
$router->post('/webhook/stripe', 'Settings\Billing\StripeWebhookController@handleWebhook');
$router->post('/webhook/braintree', 'Settings\Billing\BraintreeWebhookController@handleWebhook');