├── .github
└── dependabot.yml
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── composer.json
├── config
└── laravel-subscribers.php
├── database
└── migrations
│ └── 2018_01_01_000000_create_subscribers_table.php
├── package.json
├── phpunit.xml
├── resources
└── js
│ └── components
│ └── SubscriberForm.vue
├── routes
├── api.php
└── web.php
├── scrutinizer.yml
├── src
├── Events
│ ├── SubscriberCreated.php
│ ├── SubscriberDeleted.php
│ └── SubscriberVerified.php
├── Exceptions
│ ├── Handler.php
│ └── SubscriberVerificationException.php
├── Http
│ ├── Controllers
│ │ ├── Api
│ │ │ └── SubscriberController.php
│ │ └── SubscriberController.php
│ └── Requests
│ │ ├── DeleteSubscriberRequest.php
│ │ ├── StoreSubscriberRequest.php
│ │ └── VerifySubscriberRequest.php
├── Notifications
│ └── SubscriberVerifyEmail.php
├── Nova
│ ├── Metrics
│ │ └── NewSubscribers.php
│ └── Resources
│ │ └── Subscriber.php
├── Subscriber.php
├── SubscribersServiceProvider.php
└── Traits
│ └── CanSubscribe.php
├── tests
├── SubscriberTest.php
└── TestCase.php
└── webpack.mix.js
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | registries:
3 | git-github-com:
4 | type: git
5 | url: https://github.com
6 | username: x-access-token
7 | password: "${{secrets.GIT_GITHUB_COM_PASSWORD}}"
8 |
9 | updates:
10 | - package-ecosystem: composer
11 | directory: "/"
12 | schedule:
13 | interval: daily
14 | time: "04:00"
15 | open-pull-requests-limit: 10
16 | versioning-strategy: increase
17 | registries:
18 | - git-github-com
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /vendor
3 | npm-debug.log
4 | yarn-error.log
5 | composer.lock
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 7.1
5 | - 7.2
6 | - 7.3
7 |
8 | before_script:
9 | - travis_retry composer self-update
10 | - travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-source
11 |
12 | script:
13 | - vendor/bin/phpunit tests/
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Clément Rigo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Manage Internal Newsletter Subscribers With Laravel
2 |
3 | [](https://packagist.org/packages/mydnic/laravel-subscribers)
4 | [](LICENSE)
5 | [](https://travis-ci.com/mydnic/laravel-subscribers)
6 | [](https://scrutinizer-ci.com/g/mydnic/laravel-subscribers/)
7 |
8 |
9 | ## Installation
10 |
11 | You may use Composer to Install Laravel Subscribers:
12 |
13 | ```bash
14 | composer require mydnic/laravel-subscribers
15 | ```
16 |
17 | The package will automatically register itself
18 |
19 | You then must publish the migration with:
20 |
21 | ```bash
22 | php artisan vendor:publish --provider="Mydnic\Subscribers\SubscribersServiceProvider" --tag="subscribers-migrations"
23 | ```
24 |
25 | ## Usage
26 |
27 | In your view, you simply need to add a form that you can customize the way you want
28 |
29 | ```blade
30 |
35 |
36 | @if (session('subscribed'))
37 |
38 | {{ session('subscribed') }}
39 |
40 | @endif
41 | ```
42 |
43 |
44 | ### Delete
45 | Simply provide this link to your subscribers:
46 |
47 | ```blade
48 | unsubscribe
49 | ```
50 |
51 | This will generate a link like `/subscribers/delete?email=email@example.com`
52 |
53 | ### Subscribe manually from the user model
54 |
55 | Alternatively, you can manage the subscription of a user from the user model.
56 |
57 | In order to do that you will need to add the `CanSubscribe` trait
58 |
59 | ```php
60 | use Mydnic\Subscribers\Traits\CanSubscribe;
61 |
62 | class User extends Model
63 | {
64 | use CanSubscribe;
65 | }
66 | ```
67 |
68 | ```php
69 | // subscribe user
70 | $user->subscribe();
71 |
72 | // unsubscribe user
73 | $user->unsubscribe();
74 | ```
75 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mydnic/laravel-subscribers",
3 | "description": "Easily Manage Internal Newsletter Subscribers in Laravel",
4 | "keywords": [
5 | "laravel",
6 | "customer",
7 | "feedback"
8 | ],
9 | "license": "MIT",
10 | "homepage": "https://github.com/mydnic/laravel-subscribers",
11 | "authors": [
12 | {
13 | "name": "Clément Rigo",
14 | "email": "rigoclement@mydnic.be"
15 | }
16 | ],
17 | "require": {
18 | "php": "^7.1|8.*",
19 | "laravel/framework": ">=8.40.0"
20 | },
21 | "require-dev": {
22 | "phpunit/phpunit": "^9.5",
23 | "orchestra/testbench": "^6.17.0",
24 | "mockery/mockery": "^1.3"
25 | },
26 | "autoload": {
27 | "psr-4": {
28 | "Mydnic\\Subscribers\\": "src/"
29 | }
30 | },
31 | "autoload-dev": {
32 | "psr-4": {
33 | "Mydnic\\Subscribers\\Test\\": "tests"
34 | }
35 | },
36 | "extra": {
37 | "laravel": {
38 | "providers": [
39 | "Mydnic\\Subscribers\\SubscribersServiceProvider"
40 | ]
41 | }
42 | },
43 | "scripts": {
44 | "test": "vendor/bin/phpunit"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/config/laravel-subscribers.php:
--------------------------------------------------------------------------------
1 | env('LARAVEL_SUBSCRIBERS_VERIFY', false),
4 | 'redirect_url' => 'home',
5 | /*
6 | |--------------------------------------------------------------------------
7 | | Notifications Mail Messages
8 | |--------------------------------------------------------------------------
9 | |
10 | */
11 | 'mail' => [
12 | 'verify' => [
13 | 'expiration' => 60, // in minutes
14 | 'subject' => 'Verify Email Address',
15 | 'greeting' => 'Hello!',
16 | 'content' => [
17 | 'Please click the button below to verify your email address.'
18 | ],
19 | 'action' => 'Verify Email Address',
20 | 'footer' => [
21 | 'If you did not sign up for our newsletter, no further action is required.'
22 | ],
23 | ]
24 | ]
25 | ];
26 |
--------------------------------------------------------------------------------
/database/migrations/2018_01_01_000000_create_subscribers_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
18 | $table->string('email')->unique();
19 | $table->timestamps();
20 | $table->softDeletes();
21 | $table->timestamp('email_verified_at')->nullable();
22 | });
23 | }
24 |
25 | /**
26 | * Reverse the migrations.
27 | *
28 | * @return void
29 | */
30 | public function down()
31 | {
32 | Schema::dropIfExists('subscribers');
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "dev": "npm run development",
5 | "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
6 | "watch": "npm run development -- --watch",
7 | "watch-poll": "npm run watch -- --watch-poll",
8 | "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
9 | "prod": "npm run production",
10 | "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
11 | },
12 | "devDependencies": {
13 | "axios": "^0.18",
14 | "cross-env": "^5.1",
15 | "laravel-mix": "^2.0",
16 | "lodash": "^4.17.4",
17 | "vue": "^2.5.7"
18 | },
19 | "dependencies": {
20 | "html2canvas": "^1.0.0-alpha.12"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 | tests
15 |
16 |
17 |
18 |
19 | src/
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/resources/js/components/SubscriberForm.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
19 |
20 |
21 | Thank you for subscribing!
22 |
23 |
24 |
25 |
26 |
27 |
59 |
60 |
65 |
--------------------------------------------------------------------------------
/routes/api.php:
--------------------------------------------------------------------------------
1 | name('store');
6 |
--------------------------------------------------------------------------------
/routes/web.php:
--------------------------------------------------------------------------------
1 | name('store');
6 | Route::get('delete', 'SubscriberController@delete')->name('delete');
7 | Route::get('verify/{id}/{hash}', 'SubscriberController@verify')->name('verify');
8 |
--------------------------------------------------------------------------------
/scrutinizer.yml:
--------------------------------------------------------------------------------
1 | filter:
2 | excluded_paths: [tests/*]
3 |
4 | checks:
5 | php:
6 | remove_extra_empty_lines: true
7 | remove_php_closing_tag: true
8 | remove_trailing_whitespace: true
9 | fix_use_statements:
10 | remove_unused: true
11 | preserve_multiple: false
12 | preserve_blanklines: true
13 | order_alphabetically: true
14 | fix_php_opening_tag: true
15 | fix_linefeed: true
16 | fix_line_ending: true
17 | fix_identation_4spaces: true
18 |
--------------------------------------------------------------------------------
/src/Events/SubscriberCreated.php:
--------------------------------------------------------------------------------
1 | subscriber = $subscriber;
28 | }
29 |
30 | /**
31 | * Get the channels the event should broadcast on.
32 | *
33 | * @return \Illuminate\Broadcasting\Channel|array
34 | */
35 | public function broadcastOn()
36 | {
37 | // return new PrivateChannel('channel-name');
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Events/SubscriberDeleted.php:
--------------------------------------------------------------------------------
1 | subscriber = $subscriber;
28 | }
29 |
30 | /**
31 | * Get the channels the event should broadcast on.
32 | *
33 | * @return \Illuminate\Broadcasting\Channel|array
34 | */
35 | public function broadcastOn()
36 | {
37 | // return new PrivateChannel('channel-name');
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Events/SubscriberVerified.php:
--------------------------------------------------------------------------------
1 | subscriber = $subscriber;
28 | }
29 |
30 | /**
31 | * Get the channels the event should broadcast on.
32 | *
33 | * @return \Illuminate\Broadcasting\Channel|array
34 | */
35 | public function broadcastOn()
36 | {
37 | // return new PrivateChannel('channel-name');
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Exceptions/Handler.php:
--------------------------------------------------------------------------------
1 | all());
19 |
20 | return response()->json([
21 | 'created' => true,
22 | ], 201);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Http/Controllers/SubscriberController.php:
--------------------------------------------------------------------------------
1 | all());
23 |
24 | if (config('laravel-subscribers.verify')) {
25 | $subscriber->sendEmailVerificationNotification();
26 | return redirect()->route(config('laravel-subscribers.redirect_url'))
27 | ->with('subscribed', __('Please verify your email address!'));
28 | }
29 |
30 | return redirect()->route(config('laravel-subscribers.redirect_url'))
31 | ->with('subscribed', __('You are successfully subscribed to our list!'));
32 | }
33 |
34 | public function delete(DeleteSubscriberRequest $request)
35 | {
36 | $request->subscriber()->delete();
37 | return view('subscribe.deleted');
38 | }
39 |
40 | public function verify(VerifySubscriberRequest $request)
41 | {
42 | $subscriber = Subscriber::find($request->id);
43 | if (!hash_equals((string) $request->route('id'), (string) $subscriber->getKey())) {
44 | throw new SubscriberVerificationException;
45 | }
46 |
47 | if (!hash_equals((string) $request->route('hash'), sha1($subscriber->getEmailForVerification()))) {
48 | throw new SubscriberVerificationException;
49 | }
50 |
51 | if ($subscriber->hasVerifiedEmail()) {
52 | return $request->wantsJson()
53 | ? new Response('', 204)
54 | : redirect($this->redirectPath());
55 | }
56 |
57 | if ($subscriber->markEmailAsVerified()) {
58 | event(new SubscriberVerified($subscriber));
59 | }
60 |
61 | return $request->wantsJson()
62 | ? new Response('', 204)
63 | : redirect()->route(config('laravel-subscribers.redirect_url'))->with('verified', __('You are successfully subscribed to our list!'));
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/Http/Requests/DeleteSubscriberRequest.php:
--------------------------------------------------------------------------------
1 | 'required|email|exists:subscribers,email',
19 | ];
20 | }
21 |
22 | public function subscriber()
23 | {
24 | return Subscriber::where('email', $this->input('email'))->firstOrFail();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Http/Requests/StoreSubscriberRequest.php:
--------------------------------------------------------------------------------
1 | 'required|email|unique:subscribers,email',
21 | ];
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Http/Requests/VerifySubscriberRequest.php:
--------------------------------------------------------------------------------
1 | 'required|email|exists:subscribers,email',
19 | ];
20 | }
21 |
22 | public function subscriber()
23 | {
24 | return Subscriber::where('email', $this->input('email'))->firstOrFail();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Notifications/SubscriberVerifyEmail.php:
--------------------------------------------------------------------------------
1 | verificationUrl($notifiable);
49 |
50 | $mail = new MailMessage();
51 |
52 | $mail->subject(Lang::get(config('laravel-subscribers.mail.verify.subject', 'Verify Email Address')));
53 | $mail->greeting(Lang::get(config('laravel-subscribers.mail.verify.greeting', 'Hello!')));
54 |
55 | if (!empty(config('laravel-subscribers.mail.verify.content'))) {
56 | foreach (config('laravel-subscribers.mail.verify.content') as $value) {
57 | $mail->line(Lang::get($value));
58 | }
59 | } else {
60 | $mail->line(Lang::get('Please click the button below to verify your email address.'));
61 | }
62 |
63 | $mail->action(Lang::get(config('laravel-subscribers.mail.verify.action', 'Verify Email Address')), $verificationUrl);
64 |
65 | if (!empty(config('laravel-subscribers.mail.verify.footer'))) {
66 | foreach (config('laravel-subscribers.mail.verify.footer') as $value) {
67 | $mail->line(Lang::get($value));
68 | }
69 | } else {
70 | $mail->line(Lang::get('If you did not sign up for our newsletter, no further action is required.'));
71 | }
72 |
73 | return $mail;
74 | }
75 |
76 | /**
77 | * Get the array representation of the notification.
78 | *
79 | * @param mixed $notifiable
80 | * @return array
81 | */
82 | public function toArray($notifiable)
83 | {
84 | return [
85 | //
86 | ];
87 | }
88 |
89 | /**
90 | * Get the verification URL for the given notifiable.
91 | *
92 | * @param mixed $notifiable
93 | * @return string
94 | */
95 | protected function verificationUrl($notifiable)
96 | {
97 | return URL::temporarySignedRoute(
98 | 'subscribers.verify',
99 | Carbon::now()->addMinutes(config('laravel-subscribers.mail.verify.expiration')),
100 | [
101 | 'id' => $notifiable->getKey(),
102 | 'hash' => sha1($notifiable->getEmailForVerification()),
103 | ]
104 | );
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/Nova/Metrics/NewSubscribers.php:
--------------------------------------------------------------------------------
1 | count($request, Subscriber::class);
20 | }
21 |
22 | /**
23 | * Get the ranges available for the metric.
24 | *
25 | * @return array
26 | */
27 | public function ranges()
28 | {
29 | return [
30 | 30 => '30 Days',
31 | 60 => '60 Days',
32 | 365 => '365 Days',
33 | 'MTD' => 'Month To Date',
34 | 'QTD' => 'Quarter To Date',
35 | 'YTD' => 'Year To Date',
36 | ];
37 | }
38 |
39 | /**
40 | * Determine for how many minutes the metric should be cached.
41 | *
42 | * @return \DateTimeInterface|\DateInterval|float|int
43 | */
44 | public function cacheFor()
45 | {
46 | // return now()->addMinutes(5);
47 | }
48 |
49 | /**
50 | * Get the URI key for the metric.
51 | *
52 | * @return string
53 | */
54 | public function uriKey()
55 | {
56 | return 'new-subscribers';
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/Nova/Resources/Subscriber.php:
--------------------------------------------------------------------------------
1 | sortable(),
47 |
48 | Text::make('Email')
49 | ->sortable()
50 | ->rules('required', 'email', 'max:255')
51 | ->creationRules('unique:subscribers,email')
52 | ->updateRules('unique:subscribers,email,{{resourceId}}'),
53 | ];
54 | }
55 |
56 | /**
57 | * Get the cards available for the request.
58 | *
59 | * @param \Illuminate\Http\Request $request
60 | * @return array
61 | */
62 | public function cards(Request $request)
63 | {
64 | return [
65 | new NewSubscribers,
66 | ];
67 | }
68 |
69 | /**
70 | * Get the filters available for the resource.
71 | *
72 | * @param \Illuminate\Http\Request $request
73 | * @return array
74 | */
75 | public function filters(Request $request)
76 | {
77 | return [];
78 | }
79 |
80 | /**
81 | * Get the lenses available for the resource.
82 | *
83 | * @param \Illuminate\Http\Request $request
84 | * @return array
85 | */
86 | public function lenses(Request $request)
87 | {
88 | return [];
89 | }
90 |
91 | /**
92 | * Get the actions available for the resource.
93 | *
94 | * @param \Illuminate\Http\Request $request
95 | * @return array
96 | */
97 | public function actions(Request $request)
98 | {
99 | return [];
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/Subscriber.php:
--------------------------------------------------------------------------------
1 | SubscriberCreated::class,
26 | 'deleted' => SubscriberDeleted::class,
27 | ];
28 |
29 |
30 | /**
31 | * Determine if the user has verified their email address.
32 | *
33 | * @return bool
34 | */
35 | public function hasVerifiedEmail()
36 | {
37 | return ! is_null($this->email_verified_at);
38 | }
39 |
40 | /**
41 | * Mark the given user's email as verified.
42 | *
43 | * @return bool
44 | */
45 | public function markEmailAsVerified()
46 | {
47 | return $this->forceFill([
48 | 'email_verified_at' => $this->freshTimestamp(),
49 | ])->save();
50 | }
51 |
52 | /**
53 | * Send the email verification notification.
54 | *
55 | * @return void
56 | */
57 | public function sendEmailVerificationNotification()
58 | {
59 | $this->notify(new SubscriberVerifyEmail);
60 | }
61 |
62 | /**
63 | * Get the email address that should be used for verification.
64 | *
65 | * @return string
66 | */
67 | public function getEmailForVerification()
68 | {
69 | return $this->email;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/SubscribersServiceProvider.php:
--------------------------------------------------------------------------------
1 | app->runningInConsole()) {
18 | $this->registerPublishing();
19 | }
20 |
21 | $this->registerRoutes();
22 | }
23 |
24 | /**
25 | * Register the package's publishable resources.
26 | *
27 | * @return void
28 | */
29 | protected function registerPublishing()
30 | {
31 | $this->publishes([
32 | __DIR__ . '/../resources/js/components' => resource_path('js/components/Subscribers'),
33 | ], 'subscribers-vue-component');
34 |
35 | $this->publishes([
36 | __DIR__ . '/../database/migrations' => database_path('migrations'),
37 | ], 'subscribers-migrations');
38 |
39 | $this->publishes([
40 | __DIR__.'/../config/laravel-subscribers.php' => config_path('laravel-subscribers.php'),
41 | ], 'subscribers-config');
42 | }
43 |
44 | /**
45 | * Register the package routes.
46 | *
47 | * @return void
48 | */
49 | protected function registerRoutes()
50 | {
51 | Route::group($this->apiRouteConfiguration(), function () {
52 | $this->loadRoutesFrom(__DIR__ . '/../routes/api.php');
53 | });
54 | Route::group($this->webRouteConfiguration(), function () {
55 | $this->loadRoutesFrom(__DIR__ . '/../routes/web.php');
56 | });
57 | }
58 |
59 | /**
60 | * Get the Subscribers route group configuration array for web middleware.
61 | *
62 | * @return array
63 | */
64 | protected function webRouteConfiguration()
65 | {
66 | return [
67 | 'namespace' => 'Mydnic\Subscribers\Http\Controllers',
68 | 'as' => 'subscribers.',
69 | 'prefix' => 'subscribers',
70 | 'middleware' => 'web',
71 | ];
72 | }
73 |
74 | /**
75 | * Get the Subscribers route group configuration array for api middleware.
76 | *
77 | * @return array
78 | */
79 | protected function apiRouteConfiguration()
80 | {
81 | return [
82 | 'namespace' => 'Mydnic\Subscribers\Http\Controllers\Api',
83 | 'as' => 'subscribers.api.',
84 | 'prefix' => 'subscribers-api',
85 | 'middleware' => 'api',
86 | ];
87 | }
88 |
89 | /**
90 | * Register any package services.
91 | *
92 | * @return void
93 | */
94 | public function register()
95 | {
96 | if (! $this->app->configurationIsCached()) {
97 | $this->mergeConfigFrom(__DIR__.'/../config/laravel-subscribers.php', 'laravel-subscribers');
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/Traits/CanSubscribe.php:
--------------------------------------------------------------------------------
1 | $this->email]);
12 |
13 | if (config('laravel-subscribers.verify')) {
14 | $subscriber->sendEmailVerificationNotification();
15 | }
16 | }
17 |
18 | public function unsubscribe()
19 | {
20 | Subscriber::where('email', $this->email)->delete();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/tests/SubscriberTest.php:
--------------------------------------------------------------------------------
1 | post('/subscribers-api/subscriber', [
20 | 'email' => 'some@email.com',
21 | ]);
22 |
23 | $request->assertStatus(201);
24 |
25 | $subscriber = Subscriber::first();
26 | $this->assertEquals('some@email.com', $subscriber->email);
27 |
28 | Event::assertDispatched(SubscriberCreated::class, function ($e) use ($subscriber) {
29 | return $e->subscriber->id === $subscriber->id;
30 | });
31 | }
32 |
33 | /** @test */
34 | public function it_saves_the_subscriber_via_web()
35 | {
36 | Event::fake();
37 |
38 | $request = $this->post('/subscribers/subscriber', [
39 | 'email' => 'someweb@email.com',
40 | ]);
41 |
42 | $request->assertStatus(302);
43 |
44 | $subscriber = Subscriber::first();
45 | $this->assertEquals('someweb@email.com', $subscriber->email);
46 |
47 | Event::assertDispatched(SubscriberCreated::class, function ($e) use ($subscriber) {
48 | return $e->subscriber->id === $subscriber->id;
49 | });
50 | }
51 |
52 | /** @test */
53 | public function it_refuses_existing_subscribers()
54 | {
55 | Subscriber::create(['email' => 'some@email.com']);
56 |
57 | $request = $this->post('/subscribers-api/subscriber', [
58 | 'email' => 'some@email.com',
59 | ]);
60 |
61 | $this->assertEquals(1, Subscriber::count());
62 | }
63 |
64 | /** @test */
65 | public function it_deletes_existing_subscribers()
66 | {
67 | Event::fake();
68 |
69 | Subscriber::create(['email' => 'some@email.com']);
70 |
71 | $request = $this->get('/subscribers/delete?email=some@email.com');
72 |
73 | $this->assertEquals(0, Subscriber::count());
74 |
75 | Event::assertDispatched(SubscriberDeleted::class);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 | setUpDatabase();
17 | }
18 |
19 | protected function getPackageProviders($app)
20 | {
21 | return [SubscribersServiceProvider::class];
22 | }
23 |
24 | protected function getEnvironmentSetUp($app)
25 | {
26 | $config = $app->get('config');
27 | $config->set('logging.default', 'errorlog');
28 | $config->set('database.default', 'testbench');
29 | $config->set('database.connections.testbench', [
30 | 'driver' => 'sqlite',
31 | 'database' => ':memory:',
32 | 'prefix' => '',
33 | ]);
34 | $app->when(DatabaseEntriesRepository::class)
35 | ->needs('$connection')
36 | ->give('testbench');
37 | }
38 |
39 | protected function setUpDatabase()
40 | {
41 | Schema::dropIfExists('subscribers');
42 |
43 | Schema::create('subscribers', function (Blueprint $table) {
44 | $table->increments('id');
45 | $table->string('email')->unique();
46 | $table->timestamps();
47 | });
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/webpack.mix.js:
--------------------------------------------------------------------------------
1 | let mix = require('laravel-mix');
2 |
3 | /*
4 | |--------------------------------------------------------------------------
5 | | Mix Asset Management
6 | |--------------------------------------------------------------------------
7 | |
8 | | Mix provides a clean, fluent API for defining some Webpack build steps
9 | | for your Laravel application. By default, we are compiling the Sass
10 | | file for the application as well as bundling up all the JS files.
11 | |
12 | */
13 |
14 | mix
15 | .setPublicPath('public')
16 |
17 | .js('resources/js/kustomer.js', 'public/js')
18 |
19 | .sass('resources/sass/kustomer.scss', 'public/css')
20 |
21 | .version()
22 |
--------------------------------------------------------------------------------