Changeset View
Changeset View
Standalone View
Standalone View
src/app/Http/Controllers/API/SignupController.php
<?php | <?php | ||||
namespace App\Http\Controllers\API; | namespace App\Http\Controllers\API; | ||||
use App\Http\Controllers\Controller; | use App\Http\Controllers\Controller; | ||||
use App\Jobs\SignupVerificationEmail; | use App\Jobs\SignupVerificationEmail; | ||||
use App\Jobs\SignupVerificationSMS; | |||||
use App\Discount; | use App\Discount; | ||||
use App\Domain; | use App\Domain; | ||||
use App\Plan; | use App\Plan; | ||||
use App\Rules\SignupExternalEmail; | use App\Rules\SignupExternalEmail; | ||||
use App\Rules\SignupToken; | |||||
use App\Rules\Password; | use App\Rules\Password; | ||||
use App\Rules\UserEmailDomain; | use App\Rules\UserEmailDomain; | ||||
use App\Rules\UserEmailLocal; | use App\Rules\UserEmailLocal; | ||||
use App\SignupCode; | use App\SignupCode; | ||||
use App\SignupInvitation; | use App\SignupInvitation; | ||||
use App\User; | use App\User; | ||||
use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||||
use Illuminate\Support\Facades\DB; | use Illuminate\Support\Facades\DB; | ||||
Show All 14 Lines | class SignupController extends Controller | ||||
*/ | */ | ||||
public function plans(Request $request) | public function plans(Request $request) | ||||
{ | { | ||||
$plans = []; | $plans = []; | ||||
// Use reverse order just to have individual on left, group on right ;) | // Use reverse order just to have individual on left, group on right ;) | ||||
Plan::withEnvTenantContext()->orderByDesc('title')->get() | Plan::withEnvTenantContext()->orderByDesc('title')->get() | ||||
->map(function ($plan) use (&$plans) { | ->map(function ($plan) use (&$plans) { | ||||
// Allow themes to set custom button label | |||||
$button = \trans('theme::app.planbutton-' . $plan->title); | |||||
if ($button == 'theme::app.planbutton-' . $plan->title) { | |||||
$button = \trans('app.planbutton', ['plan' => $plan->name]); | |||||
} | |||||
$plans[] = [ | $plans[] = [ | ||||
'title' => $plan->title, | 'title' => $plan->title, | ||||
'name' => $plan->name, | 'name' => $plan->name, | ||||
'button' => \trans('app.planbutton', ['plan' => $plan->name]), | 'button' => $button, | ||||
'description' => $plan->description, | 'description' => $plan->description, | ||||
'mode' => $plan->mode ?: 'email', | |||||
]; | ]; | ||||
}); | }); | ||||
return response()->json(['status' => 'success', 'plans' => $plans]); | return response()->json(['status' => 'success', 'plans' => $plans]); | ||||
} | } | ||||
/** | /** | ||||
* Starts signup process. | * Starts signup process. | ||||
* | * | ||||
* Verifies user name and email/phone, sends verification email/sms message. | * Verifies user name and email/phone, sends verification email/sms message. | ||||
* Returns the verification code. | * Returns the verification code. | ||||
* | * | ||||
* @param \Illuminate\Http\Request $request HTTP request | * @param \Illuminate\Http\Request $request HTTP request | ||||
* | * | ||||
* @return \Illuminate\Http\JsonResponse JSON response | * @return \Illuminate\Http\JsonResponse JSON response | ||||
*/ | */ | ||||
public function init(Request $request) | public function init(Request $request) | ||||
{ | { | ||||
// Check required fields | $rules = [ | ||||
$v = Validator::make( | |||||
$request->all(), | |||||
[ | |||||
'email' => 'required', | |||||
'first_name' => 'max:128', | 'first_name' => 'max:128', | ||||
'last_name' => 'max:128', | 'last_name' => 'max:128', | ||||
'plan' => 'nullable|alpha_num|max:128', | |||||
'voucher' => 'max:32', | 'voucher' => 'max:32', | ||||
] | ]; | ||||
); | |||||
$is_phone = false; | $plan = $this->getPlan(); | ||||
$errors = $v->fails() ? $v->errors()->toArray() : []; | |||||
// Validate user email (or phone) | if ($plan->mode == 'token') { | ||||
if (empty($errors['email'])) { | $rules['token'] = ['required', 'string', new SignupToken()]; | ||||
if ($error = $this->validatePhoneOrEmail($request->email, $is_phone)) { | } else { | ||||
$errors['email'] = $error; | $rules['email'] = ['required', 'string', new SignupExternalEmail()]; | ||||
} | |||||
} | } | ||||
if (!empty($errors)) { | // Check required fields, validate input | ||||
return response()->json(['status' => 'error', 'errors' => $errors], 422); | $v = Validator::make($request->all(), $rules); | ||||
if ($v->fails()) { | |||||
return response()->json(['status' => 'error', 'errors' => $v->errors()->toArray()], 422); | |||||
} | } | ||||
// Generate the verification code | // Generate the verification code | ||||
$code = SignupCode::create([ | $code = SignupCode::create([ | ||||
'email' => $request->email, | 'email' => $plan->mode == 'token' ? $request->token : $request->email, | ||||
'first_name' => $request->first_name, | 'first_name' => $request->first_name, | ||||
'last_name' => $request->last_name, | 'last_name' => $request->last_name, | ||||
'plan' => $request->plan, | 'plan' => $plan->title, | ||||
'voucher' => $request->voucher, | 'voucher' => $request->voucher, | ||||
]); | ]); | ||||
// Send email/sms message | $response = [ | ||||
if ($is_phone) { | 'status' => 'success', | ||||
SignupVerificationSMS::dispatch($code); | 'code' => $code->code, | ||||
'mode' => $plan->mode ?: 'email', | |||||
]; | |||||
if ($plan->mode == 'token') { | |||||
// Token verification, jump to the last step | |||||
$has_domain = $plan->hasDomain(); | |||||
$response['short_code'] = $code->short_code; | |||||
$response['is_domain'] = $has_domain; | |||||
$response['domains'] = $has_domain ? [] : Domain::getPublicDomains(); | |||||
} else { | } else { | ||||
// External email verification, send an email message | |||||
SignupVerificationEmail::dispatch($code); | SignupVerificationEmail::dispatch($code); | ||||
} | } | ||||
return response()->json(['status' => 'success', 'code' => $code->code]); | return response()->json($response); | ||||
} | } | ||||
/** | /** | ||||
* Returns signup invitation information. | * Returns signup invitation information. | ||||
* | * | ||||
* @param string $id Signup invitation identifier | * @param string $id Signup invitation identifier | ||||
* | * | ||||
* @return \Illuminate\Http\JsonResponse|void | * @return \Illuminate\Http\JsonResponse|void | ||||
▲ Show 20 Lines • Show All 130 Lines • ▼ Show 20 Lines | public function signup(Request $request) | ||||
if ($v->status() !== 200) { | if ($v->status() !== 200) { | ||||
return $v; | return $v; | ||||
} | } | ||||
// Get user name/email from the verification code database | // Get user name/email from the verification code database | ||||
$code_data = $v->getData(); | $code_data = $v->getData(); | ||||
$settings = [ | $settings = [ | ||||
'external_email' => $code_data->email, | |||||
'first_name' => $code_data->first_name, | 'first_name' => $code_data->first_name, | ||||
'last_name' => $code_data->last_name, | 'last_name' => $code_data->last_name, | ||||
]; | ]; | ||||
if ($this->getPlan()->mode == 'token') { | |||||
$settings['signup_token'] = $code_data->email; | |||||
} else { | |||||
$settings['external_email'] = $code_data->email; | |||||
} | |||||
} | } | ||||
// Find the voucher discount | // Find the voucher discount | ||||
if ($request->voucher) { | if ($request->voucher) { | ||||
$discount = Discount::where('code', \strtoupper($request->voucher)) | $discount = Discount::where('code', \strtoupper($request->voucher)) | ||||
->where('active', true)->first(); | ->where('active', true)->first(); | ||||
if (!$discount) { | if (!$discount) { | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | class SignupController extends Controller | ||||
protected function getPlan() | protected function getPlan() | ||||
{ | { | ||||
$request = request(); | $request = request(); | ||||
if (!$request->plan || !$request->plan instanceof Plan) { | if (!$request->plan || !$request->plan instanceof Plan) { | ||||
// Get the plan if specified and exists... | // Get the plan if specified and exists... | ||||
if ($request->code && $request->code->plan) { | if ($request->code && $request->code->plan) { | ||||
$plan = Plan::withEnvTenantContext()->where('title', $request->code->plan)->first(); | $plan = Plan::withEnvTenantContext()->where('title', $request->code->plan)->first(); | ||||
} elseif ($request->plan) { | |||||
$plan = Plan::withEnvTenantContext()->where('title', $request->plan)->first(); | |||||
} | } | ||||
// ...otherwise use the default plan | // ...otherwise use the default plan | ||||
if (empty($plan)) { | if (empty($plan)) { | ||||
// TODO: Get default plan title from config | // TODO: Get default plan title from config | ||||
$plan = Plan::withEnvTenantContext()->where('title', 'individual')->first(); | $plan = Plan::withEnvTenantContext()->where('title', 'individual')->first(); | ||||
} | } | ||||
$request->plan = $plan; | $request->plan = $plan; | ||||
} | } | ||||
return $request->plan; | return $request->plan; | ||||
} | } | ||||
/** | /** | ||||
* Checks if the input string is a valid email address or a phone number | |||||
* | |||||
* @param string $input Email address or phone number | |||||
* @param bool $is_phone Will have been set to True if the string is valid phone number | |||||
* | |||||
* @return string Error message on validation error | |||||
*/ | |||||
protected static function validatePhoneOrEmail($input, &$is_phone = false): ?string | |||||
{ | |||||
$is_phone = false; | |||||
$v = Validator::make( | |||||
['email' => $input], | |||||
['email' => ['required', 'string', new SignupExternalEmail()]] | |||||
); | |||||
if ($v->fails()) { | |||||
return $v->errors()->toArray()['email'][0]; | |||||
} | |||||
// TODO: Phone number support | |||||
/* | |||||
$input = str_replace(array('-', ' '), '', $input); | |||||
if (!preg_match('/^\+?[0-9]{9,12}$/', $input)) { | |||||
return \trans('validation.noemailorphone'); | |||||
} | |||||
$is_phone = true; | |||||
*/ | |||||
return null; | |||||
} | |||||
/** | |||||
* Login (kolab identity) validation | * Login (kolab identity) validation | ||||
* | * | ||||
* @param string $login Login (local part of an email address) | * @param string $login Login (local part of an email address) | ||||
* @param string $domain Domain name | * @param string $domain Domain name | ||||
* @param bool $external Enables additional checks for domain part | * @param bool $external Enables additional checks for domain part | ||||
* | * | ||||
* @return array Error messages on validation error | * @return array Error messages on validation error | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 42 Lines • Show Last 20 Lines |