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') !!}
+
+ +