parent
							
								
									b607ded743
								
							
						
					
					
						commit
						a5187c751a
					
				@ -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