diff --git a/app/Http/Controllers/SubscriptionController.php b/app/Http/Controllers/SubscriptionController.php new file mode 100644 index 000000000000..3a5157def579 --- /dev/null +++ b/app/Http/Controllers/SubscriptionController.php @@ -0,0 +1,158 @@ +subscriptionService = $subscriptionService; + } + + /** + * @return \Illuminate\Http\RedirectResponse + */ + public function index() + { + return Redirect::to('settings/' . ACCOUNT_API_TOKENS); + } + + /** + * @return \Illuminate\Http\JsonResponse + */ + public function getDatatable() + { + return $this->subscriptionService->getDatatable(Auth::user()->id); + } + + /** + * @param $publicId + * + * @return \Illuminate\Contracts\View\View + */ + public function edit($publicId) + { + $subscription = Subscription::scope($publicId)->firstOrFail(); + + $data = [ + 'subscription' => $subscription, + 'method' => 'PUT', + 'url' => 'subscriptions/' . $publicId, + 'title' => trans('texts.edit_subscription'), + ]; + + return View::make('accounts.subscription', $data); + } + + /** + * @param $publicId + * + * @return \Illuminate\Http\RedirectResponse + */ + public function update($publicId) + { + return $this->save($publicId); + } + + /** + * @return \Illuminate\Http\RedirectResponse + */ + public function store() + { + return $this->save(); + } + + /** + * @return \Illuminate\Contracts\View\View + */ + public function create() + { + $data = [ + 'subscription' => null, + 'method' => 'POST', + 'url' => 'subscriptions', + 'title' => trans('texts.add_subscription'), + ]; + + return View::make('accounts.subscription', $data); + } + + /** + * @return \Illuminate\Http\RedirectResponse + */ + public function bulk() + { + $action = Input::get('bulk_action'); + $ids = Input::get('bulk_public_id'); + $count = $this->subscriptionService->bulk($ids, $action); + + Session::flash('message', trans('texts.archived_subscription')); + + return Redirect::to('settings/' . ACCOUNT_API_TOKENS); + } + + /** + * @param bool $subscriptionPublicId + * + * @return $this|\Illuminate\Http\RedirectResponse + */ + public function save($subscriptionPublicId = false) + { + if (Auth::user()->account->hasFeature(FEATURE_API)) { + $rules = [ + 'event_id' => 'required', + 'target_url' => 'required|url', + ]; + + if ($subscriptionPublicId) { + $subscription = Subscription::scope($subscriptionPublicId)->firstOrFail(); + } else { + $subscription = Subscription::createNew(); + } + + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) { + return Redirect::to($subscriptionPublicId ? 'subscriptions/edit' : 'subscriptions/create')->withInput()->withErrors($validator); + } + + $subscription->fill(request()->all()); + $subscription->save(); + + if ($subscriptionPublicId) { + $message = trans('texts.updated_subscription'); + } else { + $message = trans('texts.created_subscription'); + } + + Session::flash('message', $message); + } + + return Redirect::to('settings/' . ACCOUNT_API_TOKENS); + } +} diff --git a/app/Models/Subscription.php b/app/Models/Subscription.php index 766678a1888a..23e04ad7a0b5 100644 --- a/app/Models/Subscription.php +++ b/app/Models/Subscription.php @@ -8,15 +8,24 @@ use Illuminate\Database\Eloquent\SoftDeletes; /** * Class Subscription. */ -class Subscription extends Eloquent +class Subscription extends EntityModel { /** * @var bool */ public $timestamps = true; use SoftDeletes; + /** * @var array */ protected $dates = ['deleted_at']; + + /** + * @var array + */ + protected $fillable = [ + 'event_id', + 'target_url', + ]; } diff --git a/app/Ninja/Repositories/SubscriptionRepository.php b/app/Ninja/Repositories/SubscriptionRepository.php new file mode 100644 index 000000000000..9b11d49b3e2d --- /dev/null +++ b/app/Ninja/Repositories/SubscriptionRepository.php @@ -0,0 +1,23 @@ +where('account_subscriptions.user_id', '=', $userId) + ->whereNull('account_subscriptions.deleted_at'); + + return $query->select('account_subscriptions.public_id', 'account_subscriptions.name', 'account_subscriptions.subscription', 'account_subscriptions.public_id', 'account_subscriptions.deleted_at'); + } +} diff --git a/app/Services/SubscriptionService.php b/app/Services/SubscriptionService.php new file mode 100644 index 000000000000..fcdb26011a5e --- /dev/null +++ b/app/Services/SubscriptionService.php @@ -0,0 +1,55 @@ +subscriptionRepo = $subscriptionRepo; + $this->datatableService = $datatableService; + } + + /** + * @return SubscriptionRepository + */ + protected function getRepo() + { + return $this->subscriptionRepo; + } + + /** + * @param $userId + * + * @return \Illuminate\Http\JsonResponse + */ + public function getDatatable($userId) + { + $datatable = new SubscriptionDatatable(false); + $query = $this->subscriptionRepo->find($userId); + + return $this->datatableService->createDatatable($datatable, $query); + } +} diff --git a/database/migrations/2017_11_15_114422_add_subdomain_to_lookups.php b/database/migrations/2017_11_15_114422_add_subdomain_to_lookups.php index 9e13b79d44e8..54038152c653 100644 --- a/database/migrations/2017_11_15_114422_add_subdomain_to_lookups.php +++ b/database/migrations/2017_11_15_114422_add_subdomain_to_lookups.php @@ -3,6 +3,7 @@ use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; +use App\Models\Subscription; class AddSubdomainToLookups extends Migration { @@ -64,6 +65,29 @@ class AddSubdomainToLookups extends Migration $table->unique(['account_id', 'public_id']); }); + Schema::table('subscriptions', function ($table) { + $table->unsignedInteger('public_id')->nullable(); + $table->unsignedInteger('user_id')->nullable(); + }); + + $accountPublicIds = []; + foreach (Subscription::all() as $subscription) { + $accountId = $subscription->account_id; + if (isset($accountPublicIds[$accountId])) { + $publicId = $accountPublicIds[$accountId]; + $accountPublicIds[$accountId]++; + } else { + $publicId = 1; + $accountPublicIds[$accountId] = 2; + } + $subscription->public_id = $publicId; + $subscription->save(); + } + + Schema::table('subscriptions', function ($table) { + $table->unique(['account_id', 'public_id']); + }); + } /** @@ -99,5 +123,15 @@ class AddSubdomainToLookups extends Migration }); Schema::dropIfExists('scheduled_reports'); + + Schema::table('subscriptions', function ($table) { + $table->dropUnique('subscriptions_account_id_public_id_unique'); + }); + + Schema::table('subscriptions', function ($table) { + $table->dropColumn('public_id'); + $table->dropColumn('user_id'); + }); + } } diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index a30cfdd4441a..7c551f556c6d 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -2567,6 +2567,21 @@ $LANG = array( 'apple_pay_domain' => 'Use :domain as the domain in :link.', 'apple_pay_not_supported' => 'Sorry, Apple/Google Pay isn\'t supported', 'optional_payment_methods' => 'Optional Payment Methods', + 'add_subscription' => 'Add Subscription', + 'target_url' => 'Target URL', + 'event' => 'Event', + 'event_create_client' => 'Created Client', + 'event_create_invoice' => 'Created Invoice', + 'event_create_quote' => 'Created Quote', + 'event_create_payment' => 'Created Payment', + 'event_create_vendor' => 'Created Vendor', + 'event_update_quote' => 'Updated Quote', + 'event_delete_quote' => 'Deleted Quote', + 'event_update_invoice' => 'Updated Invoice', + 'event_delete_invoice' => 'Deleted Invoice', + 'subscriptions' => 'Subscriptions', + 'updated_subscription' => 'Successfully updated subscription', + 'created_subscription' => 'Successfully created subscription', ); diff --git a/resources/views/accounts/api_tokens.blade.php b/resources/views/accounts/api_tokens.blade.php index 608847f969ff..5769a213de79 100644 --- a/resources/views/accounts/api_tokens.blade.php +++ b/resources/views/accounts/api_tokens.blade.php @@ -29,6 +29,30 @@ ->setOptions('aoColumnDefs', [['bSortable'=>false, 'aTargets'=>[2]]]) ->render('datatable') !!} +

 

+ +
+ @if (Utils::hasFeature(FEATURE_API)) + {!! Button::primary(trans('texts.add_subscription'))->asLinkTo(URL::to('/subscriptions/create'))->appendIcon(Icon::create('plus-sign')) !!} + @endif +
+ + @include('partials.bulk_form', ['entityType' => ENTITY_TOKEN]) + + {!! Datatable::table() + ->addColumn( + trans('texts.name'), + trans('texts.token'), + trans('texts.action')) + ->setUrl(url('api/tokens/')) + ->setOptions('sPaginationType', 'bootstrap') + ->setOptions('bFilter', false) + ->setOptions('bAutoWidth', false) + ->setOptions('aoColumns', [[ "sWidth"=> "40%" ], [ "sWidth"=> "40%" ], ["sWidth"=> "20%"]]) + ->setOptions('aoColumnDefs', [['bSortable'=>false, 'aTargets'=>[2]]]) + ->render('datatable') !!} + + + @endif + + + {!! Former::close() !!} + +@stop + +@section('onReady') + $('#name').focus(); +@stop diff --git a/routes/web.php b/routes/web.php index 83c11fe47564..e1ea830522be 100644 --- a/routes/web.php +++ b/routes/web.php @@ -266,6 +266,9 @@ Route::group([ Route::get('api/tokens', 'TokenController@getDatatable'); Route::resource('tokens', 'TokenController'); Route::post('tokens/bulk', 'TokenController@bulk'); + Route::get('api/subscriptions', 'SubscriptionController@getDatatable'); + Route::resource('subscriptions', 'SubscriptionController'); + Route::post('subscriptions/bulk', 'SubscriptionController@bulk'); Route::get('api/tax_rates', 'TaxRateController@getDatatable'); Route::resource('tax_rates', 'TaxRateController');