Skip to content
This repository has been archived by the owner on Jul 12, 2022. It is now read-only.

Commit

Permalink
Release/2.0.0 (#70)
Browse files Browse the repository at this point in the history
* fix(controllers): Fix methods visibility

* fix(structure): Move routes file into Routes directory

* fix(controllers): Add missing mandatory getChannels method

* refactor(core): Improve de structure and flexibility

* refactor(core): Improve dynamic building content

* refactor(core): Use a single modal to handle notification subscription

* refactor(core): Split configuration controller from notifications one

* refactor(core): Reintroduce the subscribe state in table rendering

* refactor(core): Drop deprecated stuff

* Private subscription
partially working

* Apply fixes from StyleCI

* Better read documentation

* working private subscription and unsubscription

* Include warlofs review findings.

* Apply fixes from StyleCI

* Use AbstractNotification class as name.

* Private subscription (#1)

* Private subscription
partially working

* Apply fixes from StyleCI

* Better read documentation

* working private subscription and unsubscription

* Include warlofs review findings.

* Apply fixes from StyleCI

* Use AbstractNotification class as name.

* refactor(core): Adapt namespaces

* refactor(core): Include registration route to driver contract

* refactor(core): Enforce return to be typed

* refactor(views): Reduce blade verbosity

* prep for migrations

* migration file

* New DB Structure with working private subscription

* Apply fixes from StyleCI

* fix(modal): Include notification title into the channel modal

* docs(core): Add missing documentation block on controllers

* refactor(core): Remove various vanilla stuff

* refactor(core): Provide dynamic filters to subscription modal

* style(core): Apply styleCI complaints

* refactor(core): Add missing recipients seeding from filters

* fix(core): Fix public subscription flow

* fix(core): Fix public unsubscription flow

* fix(core): Fix filter reset on modal hide

* chore(manifest): Add Warlof as author

* fix(subscription): Remove un-needed group_id check

* docs(readme): Add UML Diagram in order to highlight architecture

* Implementing `getPublicDriverId()`- and simplifying `isSubscribed()` -
method

* refactor(jobs): Move the notification dispatcher to new architecture

Working discord notification

* Apply fixes from StyleCI

* style(refreshtoken): Move the name building inside callback

* Fix RefreshTokenDispatcher and public subscription.

* Apply fixes from StyleCI

* refactor(drivers): Drop vanilla code related to private registration flow

* Remove POC as name (#52)

* this package is much more then a proof of concept.

* UpdateOrCreate public subscription.

* Externalize affiliation json build. return null if no filter is set.

* use proper unsubscribe id

* remove group_id, as it is not needed

* change unsubscribe method to post

* Update Copyright

* Apply fixes from StyleCI

* Slack driver implementation

* Slack driver implementation

* use proper variable as channel description

* cleanup

* Move session related affiliations to `BuildAffiliationJSONAction`

* Introduce ImplementPrivateFlowException

* fix typo

* Introduce AbstractNotificationDriver and move getPublicDriverId into it.

* update copyright

* Apply fixes from StyleCI

* Kill Mail Notification
* working discord notification

* Update Job to get recent killmails

* SlackKillMailNotification

* Styling

* Apply fixes from StyleCI

* Add caching to resolve_id function

* Changelog + version bump

* remove todo

* Add Permission check to blades.

* fix naming of color

* Fix killmail dispatcher dispatching not only relevant subscribed
notifications

* fix private unsubscribe action. Before it unsubscribed every subscription
not only the one selected

* improve private subscription buttons and assure that the selected
notification gets subscribed

previously form id were not unique

* Fix affiliation type for is_loss()

* remove unused method

* Fix routes

* Feature/select affiliated filter (#66)

* preselect affiliated filters in select field.

* Apply fixes from StyleCI

* improve loading placeholder

* Update Readme for 2.x (#68)

* Update Readme for 2.x

* reduce mandatory methods

* Update changelog

* Apply fixes from StyleCI (#71)
  • Loading branch information
herpaderpaldent authored Mar 31, 2019
1 parent 7fbfb5d commit cf93781
Show file tree
Hide file tree
Showing 76 changed files with 3,349 additions and 2,046 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
# Version 2.0.0
This major release revamps seat-notifications significantly. Thanks to new co-author [warlof](https://github.com/warlof), we majorly refactoring all of seat-notification in order to introduce new notifications from within this package or from a third party application with ease.

## ATTENTION:
1. As this is a major release your subscriptions will be reset. You need to reapply your notifications.
2. Do not forget to run migrations

Please report any issues on [github](https://github.com/herpaderpaldent/seat-notifications/issues).

# Version 1.1.2
This version adds some smaller improvements:
* Delete job from dispatcher if there are no recipients for a given notification.
Expand Down
151 changes: 108 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# seat-notifications
With this [SeAT](https://github.com/eveseat/seat) Package you can setup and manage notifications. It is build to be expendend from within the package or from another package. Please read more about it further down.
With this [SeAT](https://github.com/eveseat/seat) Package you can setup and manage notifications. It is build to be expended from within the package or from another package. Please read more about it further down.

[![Latest Stable Version](https://poser.pugx.org/herpaderpaldent/seat-notifications/v/stable)](https://packagist.org/packages/herpaderpaldent/seat-notifications)
[![StyleCI](https://github.styleci.io/repos/140680541/shield?branch=master)](https://github.styleci.io/repos/140680541)
Expand Down Expand Up @@ -60,75 +60,140 @@ Notification::send($receipients, (new RefreshTokenDeletedNotification($refresh_t

where `$receipients` are a collection of modal that should receive the notification and `$refresh_token` is the deleted `refresh_token` that is passed to the constructor. In this example we use an Observer to send notifications: [Observer](https://github.com/herpaderpaldent/seat-notifications/blob/master/src/Observers/RefreshTokenObserver.php).

### Add new channels
### Architecture

If you have written a new notification channel that you would like to use for sending notifications to your users you might extend `config/services.php` similar to the provided example:
![uml_diagram](https://yuml.me/diagram/scruffy/class/[%3C%3CINotification%3E%3E%7Bbg:deepskyblue%7D]%5E-.-[AbstractNotification%7Bbg:deepskyblue%7D],[AbstractNotification]%5E[AbstractRefreshTokenNotification],[AbstractRefreshTokenNotification]%5E[DiscordRefreshTokenNotification%7Bbg:yellowgreen%7D],[AbstractRefreshTokenNotification%7Bbg:yellowgreen%7D]%5E[SlackRefreshTokenNotification%7Bbg:yellowgreen%7D],[AbstractNotification]++-%3E[%3C%3CINotificationDriver%3E%3E],[%3C%3CINotificationDriver%3E%3E]%5E-.-[DiscordNotificationDriver%7Bbg:lightseagreen%7D],[%3C%3CINotificationDriver%3E%3E%7Bbg:lightseagreen%7D]%5E-.-[SlackNotificationDriver%7Bbg:lightseagreen%7D],[AbstractNotification]uses%20-.-%3E[NotificationSubscription%7Bbg:orange%7D],[NotificationSubscription]++-%3E[NotificationRecipient%7Bbg:orange%7D],[NotificationRecipient]++-1%3E[Group%7Bbg:tomato%7D],[Group]++-%3E[User%7Bbg:tomato%7D])

### Add new drivers

If you have written a new notification driver that you would like to use for sending notifications to your users you might extend `config/services.php` similar to the provided example:

```
'seat-notification-channel' => [
'discord' => Herpaderpaldent\Seat\SeatNotifications\Http\Controllers\Discord\DiscordNotificationChannel::class,
'discord' => Herpaderpaldent\Seat\SeatNotifications\Drivers\DiscordNotificationDriver::class,
],
```

Your channel should extend [BaseNotificationChannel](https://github.com/herpaderpaldent/seat-notifications/blob/master/src/Http/Controllers/BaseNotificationChannel.php)
Your driver should extend `Herpaderpaldent\Seat\SeatNotifications\Drivers\AbstractNotificationDriver` and should contain;

```
namespace Herpaderpaldent\Seat\SeatNotifications\Http\Controllers;
use Seat\Web\Http\Controllers\Controller;
abstract class BaseNotificationChannel extends Controller
{
abstract protected function getSettingsView();
abstract protected function getRegistrationView();
}
/**
* The view name which will be used to store the channel settings.
*
* @return string
*/
public static function getSettingsView() : string;
/**
* The label which will be applied to the subscription button.
*
* @return string
*/
public static function getButtonLabel() : string;
/**
* The CSS class which have to be append into the subscription button.
*
* @return string
*/
public static function getButtonIconClass() : string;
/**
* @return array
*/
public static function getChannels() : array;
/**
* Determine if a channel has been properly setup.
*
* @return bool
*/
public static function isSetup(): bool;
```

### Add new notifications

If you want to extend the available notifications you need to extend the `seat-notification` array in `config/services.php`:

```
'seat-notification' => [
'refresh_token' => Herpaderpaldent\Seat\SeatNotifications\Http\Controllers\Notifications\RefreshTokenController::class,
],
'seat-notification' => [
// notification => [provider => implementation]
Herpaderpaldent\Seat\SeatNotifications\Notifications\RefreshToken\AbstractRefreshTokenNotification::class => [
'discord' => Herpaderpaldent\Seat\SeatNotifications\Notifications\RefreshToken\DiscordRefreshTokenNotification::class,
'slack' => Herpaderpaldent\Seat\SeatNotifications\Notifications\RefreshToken\SlackRefreshTokenNotification::class,
],
```

Your custom notification must contain the following public functions to add your notification to the users notification list:
Your abstract notification must extend `Herpaderpaldent\Seat\SeatNotifications\Notifications\AbstractNotification` and contain the following methods to add your notification to the users notification list:

```
public function getNotification()
{
return 'seatnotifications::refresh_token.notification';
}
public function getPrivateView()
{
return 'seatnotifications::refresh_token.private';
}
public function getChannelView()
{
return 'seatnotifications::refresh_token.channel';
}
/**
* Return a title for the notification which will be displayed in UI notification list.
* @return string
*/
public static function getTitle(): string;
/**
* Return a description for the notification which will be displayed in UI notification list.
* @return string
*/
public static function getDescription(): string;
/**
* Determine if a notification can target public channel (forum category, chat, etc...).
* @return bool
*/
public static function isPublic(): bool;
/**
* Determine if a notification can target personal channel (private message, e-mail, etc...).
* @return bool
*/
public static function isPersonal(): bool;
/**
* Determine the permission needed to represent driver buttons.
* @return string
*/
public static function getPermission(): string;
```

the functions should return a string containing the name of your view that should be rendered per column.

### Use BaseNotificationController
### Use Notification Dispatcher

You are absolutely free to handle your own database and recipient logic. However seat-notifications offer you a convinient and easy way to handle your subscribors in [BaseNotificationController.php](https://github.com/herpaderpaldent/seat-notifications/blob/master/src/Http/Controllers/BaseNotificationController.php)
In order to dispatch notification solely to receiver that subscribed to the notification it is advised to use a custom dispatcher job f.e.:

f.e:

````php
public function subscribeToChannel($channel_id, $via, $notification, $is_channel = false, $affiliation = null) : bool
public function handle()
{
try {
SeatNotificationRecipient::firstOrCreate(
['channel_id' => $channel_id], ['notification_channel' => $via, 'is_channel' => $is_channel]
)
->notifications()
->create(['name' => $notification, 'affiliation' => $affiliation]);
return true;
} catch (Exception $e) {
return false;
}
Redis::funnel('soft_delete:refresh_token_' . $this->refresh_token->user->id)->limit(1)->then(function () {
logger()->info('SoftDelete detected of ' . $this->refresh_token->user->name);

$recipients = NotificationRecipient::all()
->filter(function ($recipient) {
return $recipient->shouldReceive(AbstractRefreshTokenNotification::class);
});

if($recipients->isEmpty()){
logger()->debug('No Receiver found for this Notification. This job is going to be deleted.');
$this->delete();
}

$recipients->groupBy('driver')
->each(function ($grouped_recipients) {
$driver = (string) $grouped_recipients->first()->driver;
$notification_class = AbstractRefreshTokenNotification::getDriverImplementation($driver);

Notification::send($grouped_recipients, (new $notification_class($this->refresh_token)));
});

}, function () {

logger()->debug('A Soft-Delete job is already running for ' . $this->refresh_token->user->name);
$this->delete();
});
}
````
9 changes: 7 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,24 @@
"require": {
"php": ">=7.1",
"laravel/framework": "5.5.*",
"eveseat/web": "~3.0.14",
"eveseat/web": "~3.0.15",

This comment has been minimized.

Copy link
@warlof

warlof Mar 31, 2019

Collaborator

It must be ~3 otherwise you'll lock the platform on which the plugin is installed :/

At least ^3.0.

"erusev/parsedown": "^1.7",
"textalk/websocket": "1.0.*",
"restcord/restcord": "^0.3",
"php-http/curl-client": "^1.7",
"jolicode/slack-php-api": "^1.0"
"jolicode/slack-php-api": "^1.0",
"ext-json": "*"
},

"license": "MIT",
"authors": [
{
"name": "Felix Huber",
"email": "[email protected]"
},
{
"name": "Warlof Tutsimo",
"email": "[email protected]"
}
],
"extra": {
Expand Down
2 changes: 1 addition & 1 deletion src/Channels/Discord/DiscordChannel.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class DiscordChannel
public function send($notifiable, Notification $notification)
{

if (! $channel = $notifiable->channel_id) {
if (! $channel = $notifiable->driver_id) {
return;
}

Expand Down
2 changes: 1 addition & 1 deletion src/Channels/Slack/SlackChannel.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public function __construct()
public function send($notifiable, Notification $notification)
{

if (! $channel = $notifiable->channel_id) {
if (! $channel = $notifiable->driver_id) {
throw new Exception('Channel could not be found.');
}

Expand Down
5 changes: 3 additions & 2 deletions src/Commands/UpdateKillmails.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@

namespace Herpaderpaldent\Seat\SeatNotifications\Commands;

use Herpaderpaldent\Seat\SeatNotifications\Models\SeatNotification;
use Herpaderpaldent\Seat\SeatNotifications\Models\NotificationSubscription;
use Herpaderpaldent\Seat\SeatNotifications\Notifications\KillMail\AbstractKillMailNotification;
use Illuminate\Console\Command;
use Seat\Eveapi\Jobs\Killmails\Character\Detail as CharacterDetail;
use Seat\Eveapi\Jobs\Killmails\Character\Recent as CharacterRecent;
Expand All @@ -43,7 +44,7 @@ class UpdateKillmails extends Command

public function handle()
{
$subscribed_corporations = SeatNotification::where('name', 'kill_mail')
$subscribed_corporations = NotificationSubscription::where('notification', AbstractKillMailNotification::class)
->get()
->map(function ($seat_notification) {
return $seat_notification->affiliations()->corporations;
Expand Down
105 changes: 105 additions & 0 deletions src/Drivers/AbstractNotificationDriver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php
/**
* MIT License.
*
* Copyright (c) 2019. Felix Huber
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

namespace Herpaderpaldent\Seat\SeatNotifications\Drivers;

use Exception;
use Herpaderpaldent\Seat\SeatNotifications\Models\NotificationRecipient;

abstract class AbstractNotificationDriver implements INotificationDriver
{
/**
* Determine if a channel is supporting private notifications.
*
* @return bool
*/
public static function allowPersonalNotifications(): bool
{
return false;
}

/**
* Determine if a channel is supporting public notifications.
*
* @return bool
*/
public static function allowPublicNotifications(): bool
{
return false;
}

/**
* Return channel_id of user.
*
* @return string
*/
public static function getPrivateChannel(): ?string
{
return null;
}

/**
* Return the route key which have to be used in a private notification registration flow.
*
* @return string
*/
public static function getPrivateRegistrationRoute(): ?string
{
return null;
}

/**
* Return driver_id of public subscription.
*
* @param string $notification
*
* @return string
*/
public static function getPublicDriverId(string $notification) : ?string
{
try {

// get driver
$driver = key(array_filter(config('services.seat-notification-channel'), function ($value) {
return $value == get_called_class();
}));

return NotificationRecipient::where('driver', $driver)
->where('group_id', null)
->get()
->map(function ($recipient) use ($notification) {
return $recipient
->subscriptions
->filter(function ($subscription) use ($notification) {
return $subscription->notification === $notification;
});
})
->flatten()->first()->recipient->driver_id;
} catch (Exception $e) {

return null;
}
}
}
Loading

0 comments on commit cf93781

Please sign in to comment.