mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Merge branch 'v5-develop' of https://github.com/turbo124/invoiceninja into v5-develop
This commit is contained in:
commit
7129cd1e6f
@ -235,6 +235,9 @@ class InvitationController extends Controller
|
|||||||
->with('contact.client')
|
->with('contact.client')
|
||||||
->firstOrFail();
|
->firstOrFail();
|
||||||
|
|
||||||
|
if($invitation->contact->trashed())
|
||||||
|
$invitation->contact->restore();
|
||||||
|
|
||||||
auth()->guard('contact')->loginUsingId($invitation->contact->id, true);
|
auth()->guard('contact')->loginUsingId($invitation->contact->id, true);
|
||||||
|
|
||||||
$invoice = $invitation->invoice;
|
$invoice = $invitation->invoice;
|
||||||
|
@ -22,6 +22,7 @@ use Google_Client;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Cache;
|
use Illuminate\Support\Facades\Cache;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
use Microsoft\Graph\Model;
|
||||||
|
|
||||||
class ConnectedAccountController extends BaseController
|
class ConnectedAccountController extends BaseController
|
||||||
{
|
{
|
||||||
@ -81,12 +82,61 @@ class ConnectedAccountController extends BaseController
|
|||||||
return $this->handleGoogleOauth();
|
return $this->handleGoogleOauth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->input('provider') == 'microsoft') {
|
||||||
|
return $this->handleMicrosoftOauth($request);
|
||||||
|
}
|
||||||
|
|
||||||
return response()
|
return response()
|
||||||
->json(['message' => 'Provider not supported'], 400)
|
->json(['message' => 'Provider not supported'], 400)
|
||||||
->header('X-App-Version', config('ninja.app_version'))
|
->header('X-App-Version', config('ninja.app_version'))
|
||||||
->header('X-Api-Version', config('ninja.minimum_client_version'));
|
->header('X-Api-Version', config('ninja.minimum_client_version'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function handleMicrosoftOauth($request)
|
||||||
|
{
|
||||||
|
nlog($request->all());
|
||||||
|
|
||||||
|
if(!$request->has('access_token'))
|
||||||
|
return response()->json(['message' => 'No access_token parameter found!'], 400);
|
||||||
|
|
||||||
|
$graph = new \Microsoft\Graph\Graph();
|
||||||
|
$graph->setAccessToken($request->input('access_token'));
|
||||||
|
|
||||||
|
$user = $graph->createRequest("GET", "/me")
|
||||||
|
->setReturnType(Model\User::class)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
if($user){
|
||||||
|
|
||||||
|
$email = $user->getMail() ?: $user->getUserPrincipalName();
|
||||||
|
|
||||||
|
if(auth()->user()->email != $email && MultiDB::checkUserEmailExists($email))
|
||||||
|
return response()->json(['message' => ctrans('texts.email_already_register')], 400);
|
||||||
|
|
||||||
|
$connected_account = [
|
||||||
|
'email' => $email,
|
||||||
|
'oauth_user_id' => $user->getId(),
|
||||||
|
'oauth_provider_id' => 'microsoft',
|
||||||
|
'email_verified_at' =>now()
|
||||||
|
];
|
||||||
|
|
||||||
|
auth()->user()->update($connected_account);
|
||||||
|
auth()->user()->email_verified_at = now();
|
||||||
|
auth()->user()->save();
|
||||||
|
|
||||||
|
$this->setLoginCache(auth()->user());
|
||||||
|
|
||||||
|
return $this->itemResponse(auth()->user());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()
|
||||||
|
->json(['message' => ctrans('texts.invalid_credentials')], 401)
|
||||||
|
->header('X-App-Version', config('ninja.app_version'))
|
||||||
|
->header('X-Api-Version', config('ninja.minimum_client_version'));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private function handleGoogleOauth()
|
private function handleGoogleOauth()
|
||||||
{
|
{
|
||||||
$user = false;
|
$user = false;
|
||||||
|
@ -633,11 +633,23 @@ class PurchaseOrderController extends BaseController
|
|||||||
//check query parameter for email_type and set the template else use calculateTemplate
|
//check query parameter for email_type and set the template else use calculateTemplate
|
||||||
PurchaseOrderEmail::dispatch($purchase_order, $purchase_order->company);
|
PurchaseOrderEmail::dispatch($purchase_order, $purchase_order->company);
|
||||||
|
|
||||||
|
|
||||||
if (! $bulk) {
|
if (! $bulk) {
|
||||||
return response()->json(['message' => 'email sent'], 200);
|
return response()->json(['message' => 'email sent'], 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'cancel':
|
||||||
|
|
||||||
|
if($purchase_order->status_id <= PurchaseOrder::STATUS_SENT)
|
||||||
|
{
|
||||||
|
$purchase_order->status_id = PurchaseOrder::STATUS_CANCELLED;
|
||||||
|
$purchase_order->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $bulk) {
|
||||||
|
return $this->listResponse($purchase_order);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return response()->json(['message' => ctrans('texts.action_unavailable', ['action' => $action])], 400);
|
return response()->json(['message' => ctrans('texts.action_unavailable', ['action' => $action])], 400);
|
||||||
break;
|
break;
|
||||||
|
@ -158,7 +158,7 @@ class UserController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function create(CreateUserRequest $request)
|
public function create(CreateUserRequest $request)
|
||||||
{
|
{
|
||||||
$user = UserFactory::create(auth()->user()->account->id);
|
$user = UserFactory::create(auth()->user()->account_id);
|
||||||
|
|
||||||
return $this->itemResponse($user);
|
return $this->itemResponse($user);
|
||||||
}
|
}
|
||||||
|
@ -63,35 +63,57 @@ class PasswordProtection
|
|||||||
|
|
||||||
//user is attempting to reauth with OAuth - check the token value
|
//user is attempting to reauth with OAuth - check the token value
|
||||||
//todo expand this to include all OAuth providers
|
//todo expand this to include all OAuth providers
|
||||||
$user = false;
|
if(auth()->user()->oauth_provider_id == 'google')
|
||||||
$google = new Google();
|
{
|
||||||
$user = $google->getTokenResponse(request()->header('X-API-OAUTH-PASSWORD'));
|
$user = false;
|
||||||
|
$google = new Google();
|
||||||
if (is_array($user)) {
|
$user = $google->getTokenResponse(request()->header('X-API-OAUTH-PASSWORD'));
|
||||||
|
|
||||||
$query = [
|
|
||||||
'oauth_user_id' => $google->harvestSubField($user),
|
|
||||||
'oauth_provider_id'=> 'google'
|
|
||||||
];
|
|
||||||
|
|
||||||
//If OAuth and user also has a password set - check both
|
if (is_array($user)) {
|
||||||
if ($existing_user = MultiDB::hasUser($query) && auth()->user()->company()->oauth_password_required && auth()->user()->has_password && Hash::check(auth()->user()->password, $x_api_password)) {
|
|
||||||
|
$query = [
|
||||||
|
'oauth_user_id' => $google->harvestSubField($user),
|
||||||
|
'oauth_provider_id'=> 'google'
|
||||||
|
];
|
||||||
|
|
||||||
nlog("existing user with password");
|
//If OAuth and user also has a password set - check both
|
||||||
|
if ($existing_user = MultiDB::hasUser($query) && auth()->user()->company()->oauth_password_required && auth()->user()->has_password && Hash::check(auth()->user()->password, $x_api_password)) {
|
||||||
|
|
||||||
|
nlog("existing user with password");
|
||||||
|
|
||||||
|
Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout);
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
elseif($existing_user = MultiDB::hasUser($query) && !auth()->user()->company()->oauth_password_required){
|
||||||
|
|
||||||
|
nlog("existing user without password");
|
||||||
|
|
||||||
|
Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout);
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
elseif(auth()->user()->oauth_provider_id == 'microsoft')
|
||||||
|
{
|
||||||
|
try{
|
||||||
|
$payload = json_decode(base64_decode(str_replace('_', '/', str_replace('-','+',explode('.', request()->header('X-API-OAUTH-PASSWORD'))[1]))));
|
||||||
|
}
|
||||||
|
catch(\Exception $e){
|
||||||
|
nlog("could not decode microsoft response");
|
||||||
|
return response()->json(['message' => 'Could not decode the response from Microsoft'], 412);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($payload->preferred_username == auth()->user()->email){
|
||||||
|
|
||||||
Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout);
|
Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout);
|
||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
elseif($existing_user = MultiDB::hasUser($query) && !auth()->user()->company()->oauth_password_required){
|
|
||||||
|
|
||||||
nlog("existing user without password");
|
|
||||||
|
|
||||||
Cache::put(auth()->user()->hashed_id.'_'.auth()->user()->account_id.'_logged_in', Str::random(64), $timeout);
|
|
||||||
return $next($request);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return response()->json($error, 412);
|
return response()->json($error, 412);
|
||||||
|
|
||||||
|
|
||||||
|
@ -200,6 +200,14 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
|
|
||||||
$user = User::find($this->decodePrimaryKey($sending_user));
|
$user = User::find($this->decodePrimaryKey($sending_user));
|
||||||
|
|
||||||
|
/* Always ensure the user is set on the correct account */
|
||||||
|
if($user->account_id != $this->company->account_id){
|
||||||
|
|
||||||
|
$this->nmo->settings->email_sending_method = 'default';
|
||||||
|
return $this->setMailDriver();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
nlog("Sending via {$user->name()}");
|
nlog("Sending via {$user->name()}");
|
||||||
|
|
||||||
$token = $this->refreshOfficeToken($user);
|
$token = $this->refreshOfficeToken($user);
|
||||||
@ -236,6 +244,14 @@ class NinjaMailerJob implements ShouldQueue
|
|||||||
|
|
||||||
$user = User::find($this->decodePrimaryKey($sending_user));
|
$user = User::find($this->decodePrimaryKey($sending_user));
|
||||||
|
|
||||||
|
/* Always ensure the user is set on the correct account */
|
||||||
|
if($user->account_id != $this->company->account_id){
|
||||||
|
|
||||||
|
$this->nmo->settings->email_sending_method = 'default';
|
||||||
|
return $this->setMailDriver();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
nlog("Sending via {$user->name()}");
|
nlog("Sending via {$user->name()}");
|
||||||
|
|
||||||
$google = (new Google())->init();
|
$google = (new Google())->init();
|
||||||
|
@ -255,6 +255,7 @@ class InstantPayment
|
|||||||
'tokens' => $tokens,
|
'tokens' => $tokens,
|
||||||
'payment_method_id' => $payment_method_id,
|
'payment_method_id' => $payment_method_id,
|
||||||
'amount_with_fee' => $invoice_totals + $fee_totals,
|
'amount_with_fee' => $invoice_totals + $fee_totals,
|
||||||
|
'client' => $client,
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($is_credit_payment || $totals <= 0) {
|
if ($is_credit_payment || $totals <= 0) {
|
||||||
|
@ -51,7 +51,6 @@ class PurchaseOrderService
|
|||||||
|
|
||||||
// //TODO implement design, footer, terms
|
// //TODO implement design, footer, terms
|
||||||
|
|
||||||
|
|
||||||
// /* If client currency differs from the company default currency, then insert the client exchange rate on the model.*/
|
// /* If client currency differs from the company default currency, then insert the client exchange rate on the model.*/
|
||||||
// if (!isset($this->purchase_order->exchange_rate) && $this->purchase_order->client->currency()->id != (int)$this->purchase_order->company->settings->currency_id)
|
// if (!isset($this->purchase_order->exchange_rate) && $this->purchase_order->client->currency()->id != (int)$this->purchase_order->company->settings->currency_id)
|
||||||
// $this->purchase_order->exchange_rate = $this->purchase_order->client->currency()->exchange_rate;
|
// $this->purchase_order->exchange_rate = $this->purchase_order->client->currency()->exchange_rate;
|
||||||
@ -89,7 +88,6 @@ class PurchaseOrderService
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function touchPdf($force = false)
|
public function touchPdf($force = false)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
4
public/flutter_service_worker.js
vendored
4
public/flutter_service_worker.js
vendored
@ -8,7 +8,7 @@ const RESOURCES = {
|
|||||||
"canvaskit/profiling/canvaskit.js": "ae2949af4efc61d28a4a80fffa1db900",
|
"canvaskit/profiling/canvaskit.js": "ae2949af4efc61d28a4a80fffa1db900",
|
||||||
"canvaskit/profiling/canvaskit.wasm": "95e736ab31147d1b2c7b25f11d4c32cd",
|
"canvaskit/profiling/canvaskit.wasm": "95e736ab31147d1b2c7b25f11d4c32cd",
|
||||||
"canvaskit/canvaskit.wasm": "4b83d89d9fecbea8ca46f2f760c5a9ba",
|
"canvaskit/canvaskit.wasm": "4b83d89d9fecbea8ca46f2f760c5a9ba",
|
||||||
"/": "17a515c261fe3010e0533ce4573dca71",
|
"/": "a74757af1ea3d863d3b901f549f66929",
|
||||||
"flutter.js": "0816e65a103ba8ba51b174eeeeb2cb67",
|
"flutter.js": "0816e65a103ba8ba51b174eeeeb2cb67",
|
||||||
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
|
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
|
||||||
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
|
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
|
||||||
@ -39,7 +39,7 @@ const RESOURCES = {
|
|||||||
"assets/assets/images/payment_types/other.png": "d936e11fa3884b8c9f1bd5c914be8629",
|
"assets/assets/images/payment_types/other.png": "d936e11fa3884b8c9f1bd5c914be8629",
|
||||||
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "b62641afc9ab487008e996a5c5865e56",
|
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "b62641afc9ab487008e996a5c5865e56",
|
||||||
"assets/NOTICES": "9b6b63256d3a6491659b71127ee9f3b6",
|
"assets/NOTICES": "9b6b63256d3a6491659b71127ee9f3b6",
|
||||||
"main.dart.js": "c2902a32d34abff107d9e1e71c2858b2"
|
"main.dart.js": "943526b26dd93b9a38f54ae32cdf6795"
|
||||||
};
|
};
|
||||||
|
|
||||||
// The application shell files that are downloaded before a service worker can
|
// The application shell files that are downloaded before a service worker can
|
||||||
|
135202
public/main.dart.js
vendored
135202
public/main.dart.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
131898
public/main.foss.dart.js
vendored
131898
public/main.foss.dart.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4558
public/main.profile.dart.js
vendored
4558
public/main.profile.dart.js
vendored
File diff suppressed because one or more lines are too long
@ -212,6 +212,7 @@ Route::group(['middleware' => ['throttle:100,1', 'api_db', 'token_auth', 'locale
|
|||||||
Route::get('purchase_orders/{purchase_order}/{action}', 'PurchaseOrderController@action')->name('purchase_orders.action');
|
Route::get('purchase_orders/{purchase_order}/{action}', 'PurchaseOrderController@action')->name('purchase_orders.action');
|
||||||
|
|
||||||
Route::get('users', 'UserController@index');
|
Route::get('users', 'UserController@index');
|
||||||
|
Route::get('users/create', 'UserController@create')->middleware('password_protected');
|
||||||
Route::get('users/{user}', 'UserController@show')->middleware('password_protected');
|
Route::get('users/{user}', 'UserController@show')->middleware('password_protected');
|
||||||
Route::put('users/{user}', 'UserController@update')->middleware('password_protected');
|
Route::put('users/{user}', 'UserController@update')->middleware('password_protected');
|
||||||
Route::post('users', 'UserController@store')->middleware('password_protected');
|
Route::post('users', 'UserController@store')->middleware('password_protected');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user