Compare commits
1 Commits
main
...
developmen
Author | SHA1 | Date |
---|---|---|
Andrew | a5187c751a | 4 years ago |
@ -0,0 +1,158 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
# -*- coding: utf-8 -*- |
||||||
|
|
||||||
|
"""------------------------------------------------------------------------------------------- |
||||||
|
-- IMPORTS |
||||||
|
-------------------------------------------------------------------------------------------""" |
||||||
|
|
||||||
|
""" --- PYTHON IMPORTS --- """ |
||||||
|
import os |
||||||
|
from os.path import dirname, abspath |
||||||
|
|
||||||
|
""" --- STASHR CORE IMPORTS --- """ |
||||||
|
from stashr import log, utils |
||||||
|
from stashr import database as stashr_database |
||||||
|
from stashr.stashr import stashr_notification, stashr_notification |
||||||
|
from stashr.api import create_json_return |
||||||
|
|
||||||
|
""" --- STASHR PLUGIN IMPORTS --- """ |
||||||
|
from . import forms |
||||||
|
from .config import pushconfig |
||||||
|
|
||||||
|
""" --- STASHR PLUGIN DEPENDENCY IMPORTS --- """ |
||||||
|
try: |
||||||
|
from pushbullet import Pushbullet |
||||||
|
except: |
||||||
|
utils.install_package('pushbullet.py') |
||||||
|
from pushbullet import Pushbullet |
||||||
|
|
||||||
|
""" --- FLASK EXTENSION IMPORTS --- """ |
||||||
|
from flask_login import login_required, current_user |
||||||
|
|
||||||
|
""" --- STASHR DEPENDENCY IMPORTS --- """ |
||||||
|
from flask import Blueprint, render_template, request, redirect, flash, url_for |
||||||
|
|
||||||
|
""" --- CREATE LOGGER --- """ |
||||||
|
logger = log.stashr_logger(__name__) |
||||||
|
|
||||||
|
"""------------------------------------------------------------------------------------------- |
||||||
|
-- PLUGIN |
||||||
|
-------------------------------------------------------------------------------------------""" |
||||||
|
|
||||||
|
__plugin_name__ = "Stashr Pushbullet" |
||||||
|
__version__ = "0.1.0" |
||||||
|
__author__ = "Stashr" |
||||||
|
__description__ = "Send notifications via Pushbullet" |
||||||
|
|
||||||
|
"""------------------------------ |
||||||
|
- PUSHBULLET OBJECT |
||||||
|
------------------------------""" |
||||||
|
|
||||||
|
pb = None |
||||||
|
pb_active = False |
||||||
|
|
||||||
|
"""------------------------------ |
||||||
|
- PLUGIN ROUTES |
||||||
|
------------------------------""" |
||||||
|
|
||||||
|
""" --- DEFINE BLUEPRINT --- """ |
||||||
|
bp = Blueprint('pushbullet', __name__, root_path=dirname(abspath(__file__)), template_folder='templates', static_folder='static') |
||||||
|
|
||||||
|
""" --- PAGES --- """ |
||||||
|
|
||||||
|
@bp.route('/settings', methods=['GET', 'POST']) |
||||||
|
@login_required |
||||||
|
def pushbullet_settings_page(): |
||||||
|
|
||||||
|
if current_user.role != 'admin': |
||||||
|
flash('Permission Denied', 'error') |
||||||
|
return redirect(url_for('index_page')) |
||||||
|
|
||||||
|
settings_form = forms.settings_form() |
||||||
|
|
||||||
|
if request.method == 'POST': |
||||||
|
if settings_form.validate(): |
||||||
|
pushconfig['PUSHBULLET']['api_key'] = settings_form.api_key.data |
||||||
|
pushconfig['PUSHBULLET']['channel'] = settings_form.channel.data |
||||||
|
pushconfig.write() |
||||||
|
define_pushbullet() |
||||||
|
flash('Pushbullet Settings Updated', 'success') |
||||||
|
else: |
||||||
|
for error in settings_form.errors.items(): |
||||||
|
flash(f'{error[0]}: {error[1]}', 'error') |
||||||
|
|
||||||
|
return render_template( |
||||||
|
'pushbullet_settings.html', |
||||||
|
title='Pushbullet Settings', |
||||||
|
settings_form=settings_form |
||||||
|
) |
||||||
|
|
||||||
|
|
||||||
|
""" --- API --- """ |
||||||
|
|
||||||
|
@bp.route('/api/settings', methods=['GET']) |
||||||
|
def api_get_settings(): |
||||||
|
|
||||||
|
user = current_user |
||||||
|
|
||||||
|
if not user.is_authenticated: |
||||||
|
api_key = request.args.get('api_key') |
||||||
|
if api_key == "": |
||||||
|
return create_json_return('100') |
||||||
|
user = stashr_database.session \ |
||||||
|
.query(stashr_database.Users) \ |
||||||
|
.filter(stashr_database.Users.api_key == api_key) \ |
||||||
|
.first() |
||||||
|
|
||||||
|
if user is None: |
||||||
|
return create_json_return('100') |
||||||
|
|
||||||
|
if user.role.lower() != 'admin': |
||||||
|
return create_json_return('401') |
||||||
|
|
||||||
|
settings = pushconfig |
||||||
|
|
||||||
|
return create_json_return('200', results=settings) |
||||||
|
|
||||||
|
"""------------------------------ |
||||||
|
- PLUGIN FUNCTIONS |
||||||
|
------------------------------""" |
||||||
|
|
||||||
|
# --- Subscribe to stashr_notifications signal --- # |
||||||
|
@stashr_notification.connect |
||||||
|
def send_notification(*args, **kwargs): |
||||||
|
|
||||||
|
global pb |
||||||
|
global pb_active |
||||||
|
|
||||||
|
if not pb_active: |
||||||
|
define_pushbullet() |
||||||
|
|
||||||
|
if 'title' in kwargs and 'message' in kwargs: |
||||||
|
pb_channel = pb.get_channel(pushconfig['PUSHBULLET']['channel']) |
||||||
|
pb_channel.push_note(kwargs['title'], kwargs['message']) |
||||||
|
|
||||||
|
|
||||||
|
def define_pushbullet(): |
||||||
|
global pb |
||||||
|
global pb_active |
||||||
|
try: |
||||||
|
pb = Pushbullet(pushconfig['PUSHBULLET']['api_key']) |
||||||
|
pb_active = True |
||||||
|
except Exception as e: |
||||||
|
logger.error(e) |
||||||
|
|
||||||
|
"""------------------------------ |
||||||
|
- REGISTER PLUGIN |
||||||
|
------------------------------""" |
||||||
|
|
||||||
|
def register(): |
||||||
|
return dict( |
||||||
|
bep=dict( |
||||||
|
blueprint=bp, |
||||||
|
prefix='/pushbullet' |
||||||
|
), |
||||||
|
tep = dict( |
||||||
|
settings_menu='pushbullet_tep_settings_menu.html', |
||||||
|
) |
||||||
|
) |
@ -0,0 +1,59 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
# -*- coding: utf-8 -*- |
||||||
|
|
||||||
|
"""------------------------------------------------------------------------------------------- |
||||||
|
-- IMPORTS |
||||||
|
-------------------------------------------------------------------------------------------""" |
||||||
|
|
||||||
|
""" --- PYTHON IMPORTS --- """ |
||||||
|
import os, io, shutil |
||||||
|
from os.path import dirname, abspath |
||||||
|
|
||||||
|
from configobj import ConfigObj |
||||||
|
from validate import Validator |
||||||
|
|
||||||
|
"""------------------------------------------------------------------------------------------- |
||||||
|
-- PUSHBULLET CONFIG |
||||||
|
-------------------------------------------------------------------------------------------""" |
||||||
|
|
||||||
|
class PushConfig(ConfigObj): |
||||||
|
|
||||||
|
configspec = u""" |
||||||
|
[PUSHBULLET] |
||||||
|
api_key = string(default='') |
||||||
|
channel = string(default='') |
||||||
|
""" |
||||||
|
|
||||||
|
def __init__(self): |
||||||
|
super(PushConfig, self).__init__() |
||||||
|
|
||||||
|
configspecfile = os.path.join( |
||||||
|
dirname(abspath(__file__)), |
||||||
|
'configspec.ini' |
||||||
|
) |
||||||
|
|
||||||
|
if not os.path.exists(configspecfile): |
||||||
|
with open(configspecfile, 'w') as fd: |
||||||
|
shutil.copyfileobj(io.StringIO(PushConfig.configspec), fd) |
||||||
|
|
||||||
|
self.filename = os.path.join( |
||||||
|
dirname(abspath(__file__)), |
||||||
|
'config.ini' |
||||||
|
) |
||||||
|
self.configspec = configspecfile |
||||||
|
self.encoding = "UTF8" |
||||||
|
|
||||||
|
tmp = ConfigObj(self.filename, configspec=self.configspec, encoding=self.encoding) |
||||||
|
validator = Validator() |
||||||
|
tmp.validate(validator, copy=True) |
||||||
|
|
||||||
|
self.merge(tmp) |
||||||
|
|
||||||
|
if not os.path.exists(self.filename): |
||||||
|
self.write() |
||||||
|
|
||||||
|
"""------------------------------------------------------------------------------------------- |
||||||
|
-- CONFIGURATION DEFINITION |
||||||
|
-------------------------------------------------------------------------------------------""" |
||||||
|
|
||||||
|
pushconfig = PushConfig() |
@ -0,0 +1,37 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
# -*- coding: utf-8 -*- |
||||||
|
|
||||||
|
"""------------------------------------------------------------------------------------------- |
||||||
|
-- IMPORTS |
||||||
|
-------------------------------------------------------------------------------------------""" |
||||||
|
|
||||||
|
""" --- HUEY IMPORT --- """ |
||||||
|
""" --- PYTHON IMPORTS --- """ |
||||||
|
""" --- STASHR DEPENDENCY IMPORTS --- """ |
||||||
|
""" --- STASHR CORE IMPORTS --- """ |
||||||
|
from stashr import log, database |
||||||
|
|
||||||
|
""" --- FLASK EXTENSION IMPORTS --- """ |
||||||
|
from flask_wtf import FlaskForm |
||||||
|
|
||||||
|
from wtforms import StringField, SubmitField |
||||||
|
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError, NumberRange |
||||||
|
|
||||||
|
""" --- CREATE LOGGER --- """ |
||||||
|
logger = log.stashr_logger(__name__) |
||||||
|
|
||||||
|
"""------------------------------------------------------------------------------------------- |
||||||
|
-- FORMS |
||||||
|
-------------------------------------------------------------------------------------------""" |
||||||
|
|
||||||
|
class settings_form(FlaskForm): |
||||||
|
|
||||||
|
api_key = StringField( |
||||||
|
'Pushbullet API Key', |
||||||
|
) |
||||||
|
channel = StringField( |
||||||
|
'Pushbullet Channel', |
||||||
|
) |
||||||
|
settings_button = SubmitField( |
||||||
|
'Save', |
||||||
|
) |
@ -0,0 +1,126 @@ |
|||||||
|
{% extends "settings_page.html" %} |
||||||
|
|
||||||
|
{% block header_script_files %} |
||||||
|
<script src="https://unpkg.com/axios/dist/axios.min.js"></script> |
||||||
|
{% endblock %} |
||||||
|
|
||||||
|
{% block settings_pane %} |
||||||
|
|
||||||
|
<div id="app"> |
||||||
|
<settings ref="settings" v-bind:settings="settings"></settings> |
||||||
|
<modals ref="modal" v-bind:settings="settings"></modals> |
||||||
|
</div> |
||||||
|
|
||||||
|
{% endblock %} |
||||||
|
|
||||||
|
{% block script %} |
||||||
|
|
||||||
|
Vue.component('settings', { |
||||||
|
props: ['settings'], |
||||||
|
template: ` |
||||||
|
<div class="row r-10 m-2"> |
||||||
|
<div class="col col-12"> |
||||||
|
<div class="row"> |
||||||
|
<div class="col-sm-12 col-md-6 text-center text-md-start"> |
||||||
|
<h2>Thumbnailer</h2> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<hr /> |
||||||
|
<div class="row"> |
||||||
|
<ul class="nav nav-tabs" id="myTab" role="tablist"> |
||||||
|
<li class="nav-item" role="presentation"> |
||||||
|
<button class="nav-link active" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings" type="button" role="tab" aria-controls="settings" aria-selected="true">Settings</button> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
<div class="tab-content py-2" id="myTabContent"> |
||||||
|
<div class="tab-pane fade show active" id="settings" role="tabpanel" aria-labelledby="settings-tab"> |
||||||
|
<div class="row"> |
||||||
|
<table class="table table-striped"> |
||||||
|
<tbody> |
||||||
|
<tr> |
||||||
|
<th scope="row">{{ settings_form.api_key.label.text }}</th><td>[[ settings.PUSHBULLET.api_key ]]</td> |
||||||
|
</tr> |
||||||
|
<tr> |
||||||
|
<th scope="row">{{ settings_form.channel.label.text }}</th><td>[[ settings.PUSHBULLET.channel ]]</td> |
||||||
|
</tr> |
||||||
|
</tbody> |
||||||
|
</table> |
||||||
|
</div> |
||||||
|
<div class="row w-100"> |
||||||
|
<div class="col-12 text-end my-2"> |
||||||
|
<button type="button" class="btn btn-info" data-bs-toggle="modal" data-bs-target="#settingsModal">Modify Settings</button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
`, |
||||||
|
methods: {}, |
||||||
|
delimiters: ["[[","]]"] |
||||||
|
}) |
||||||
|
|
||||||
|
Vue.component('modals',{ |
||||||
|
props: ['settings'], |
||||||
|
template: ` |
||||||
|
<div> |
||||||
|
<div class="modal" id="settingsModal" role="dialog" aria-labelledby="settingsModal" aria-hidden="true"> |
||||||
|
<div class="modal-dialog modal-dialog-centered" role="document"> |
||||||
|
<div class="modal-content"> |
||||||
|
<div class="modal-header"> |
||||||
|
<h5 class="modal-title" id="notesModalTitle"> |
||||||
|
Modify App Settings |
||||||
|
</h5> |
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> |
||||||
|
</div> |
||||||
|
|
||||||
|
<form method="POST"> |
||||||
|
<div class="modal-body"> |
||||||
|
|
||||||
|
{{ settings_form.csrf_token }} |
||||||
|
|
||||||
|
<div class="mb-3"> |
||||||
|
{{ settings_form.api_key.label }} |
||||||
|
{{ settings_form.api_key(class_='form-control', placeholder=settings_form.api_key.label.text) }} |
||||||
|
</div> |
||||||
|
<div class="mb-3"> |
||||||
|
{{ settings_form.channel.label }} |
||||||
|
{{ settings_form.channel(class_='form-control', placeholder=settings_form.channel.label.text) }} |
||||||
|
</div> |
||||||
|
|
||||||
|
</div> |
||||||
|
<div class="modal-footer"> |
||||||
|
{{ settings_form.settings_button(class_='btn btn-success') }} |
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button> |
||||||
|
</div> |
||||||
|
</form> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
`, |
||||||
|
methods: {}, |
||||||
|
delimiters: ["[[","]]"] |
||||||
|
}) |
||||||
|
|
||||||
|
var app = new Vue({ |
||||||
|
el: '#app', |
||||||
|
data: { |
||||||
|
settings: [] |
||||||
|
}, |
||||||
|
created() { |
||||||
|
this.getSettings() |
||||||
|
}, |
||||||
|
methods: { |
||||||
|
getSettings() { |
||||||
|
axios.get('{{ url_for('pushbullet.api_get_settings') }}') |
||||||
|
.then(res => { |
||||||
|
this.settings = res.data.results; |
||||||
|
}) |
||||||
|
} |
||||||
|
}, |
||||||
|
delimiters: ["[[","]]"] |
||||||
|
}) |
||||||
|
|
||||||
|
{% endblock %} |
@ -0,0 +1,6 @@ |
|||||||
|
<li class="nav-item"> |
||||||
|
<a class="nav-link{% if request.path == url_for('pushbullet.pushbullet_settings_page') %} active{% endif %}" href="{{ url_for('pushbullet.pushbullet_settings_page') }}"> |
||||||
|
<i class="fas fa-bell"></i> |
||||||
|
Pushbullet |
||||||
|
</a> |
||||||
|
</li> |
Loading…
Reference in new issue