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();
}
}