forked from platypush/platypush
Compare commits
127 commits
master
...
29-generic
Author | SHA1 | Date | |
---|---|---|---|
486cd66885 | |||
72c7444a45 | |||
951950c864 | |||
d7278857e5 | |||
3e6ebdd23b | |||
8cd5cb3338 | |||
1af7ece881 | |||
5c68365188 | |||
7f575bacaa | |||
5995d045e1 | |||
c89ed24f4b | |||
1b791156bd | |||
e617fc75d4 | |||
041f64c80f | |||
aa5b52db2f | |||
5f09d449f4 | |||
6ec8a991df | |||
958ef6b987 | |||
16c55b45f6 | |||
b9b7404230 | |||
c0ffea681f | |||
2aab1d090d | |||
2cc80e7f16 | |||
deb25196d2 | |||
1880a99052 | |||
3513ee3e1c | |||
0d0995d71d | |||
2898a33752 | |||
0919a0055d | |||
5b3e1317f4 | |||
1df71cb54a | |||
0689e05e96 | |||
89560e7c38 | |||
30dfdeecb0 | |||
f57f940d57 | |||
117f92e5b4 | |||
a5541c33b0 | |||
b23f45f45e | |||
088cf23958 | |||
e8f4b7c10e | |||
dd12d57552 | |||
5aa3750807 | |||
f760d44224 | |||
8d91fec771 | |||
c22c17a55d | |||
46df3a6a98 | |||
8e06b8c727 | |||
30a024befb | |||
b16af0a97f | |||
c7970842d7 | |||
7df67aca82 | |||
d29b377cf1 | |||
8d57cf06c2 | |||
975d37c562 | |||
90f067de61 | |||
f45df5d4d3 | |||
975991ba69 | |||
d22fbcd9db | |||
47f8520f3b | |||
d261b9bb9b | |||
9981cc4746 | |||
3e4b13d20f | |||
321a61d06d | |||
b22df768eb | |||
8e2154f2b5 | |||
a9751f21f1 | |||
135965176d | |||
ef6b57df31 | |||
7d4bd20df0 | |||
e6bfa1c50f | |||
332c91252c | |||
b35c761a43 | |||
08c0779347 | |||
595ebe49ca | |||
548d487e73 | |||
20530c2b6d | |||
9ddcf5eaeb | |||
2aa8778078 | |||
72617b4b75 | |||
be4d1e8e01 | |||
db4ad5825e | |||
4471001110 | |||
f17245e8c7 | |||
67ff585f6c | |||
17615ff028 | |||
532217be12 | |||
f301fd7e69 | |||
58861afb1c | |||
8ec9c8f203 | |||
3435f591eb | |||
19223bbbe1 | |||
453652ef76 | |||
b2ff66aa62 | |||
655d56f4da | |||
f52b556219 | |||
947b50b937 | |||
db7c2095ea | |||
e40b668380 | |||
d3dc86a5e2 | |||
28026b0428 | |||
44707731a8 | |||
948f37afd4 | |||
3b4f7d3dad | |||
2eeb1d4fea | |||
26ffc0b0e1 | |||
7b1a63e287 | |||
1c6ff2fa49 | |||
d311629403 | |||
d52ae2fb80 | |||
061268cdaf | |||
91ff47167b | |||
fe0f3202fe | |||
8a70f1d38e | |||
4b7eeaa4ed | |||
b43ed169c7 | |||
0dac2c0e92 | |||
28b3672432 | |||
9f2793118b | |||
9d9ec1dc59 | |||
b9c78ad913 | |||
91ff8d811f | |||
783238642d | |||
53da19b638 | |||
7459f0115b | |||
2c4c27855d | |||
9c25a131fa | |||
4ee7e4db29 |
541 changed files with 8138 additions and 2275 deletions
|
@ -11,6 +11,7 @@ repos:
|
|||
- id: check-xml
|
||||
- id: check-symlinks
|
||||
- id: check-added-large-files
|
||||
args: ['--maxkb=1500']
|
||||
|
||||
- repo: https://github.com/Lucas-C/pre-commit-hooks-nodejs
|
||||
rev: v1.1.2
|
||||
|
|
|
@ -20,6 +20,7 @@ Events
|
|||
platypush/events/custom.rst
|
||||
platypush/events/dbus.rst
|
||||
platypush/events/distance.rst
|
||||
platypush/events/entities.rst
|
||||
platypush/events/file.rst
|
||||
platypush/events/foursquare.rst
|
||||
platypush/events/geo.rst
|
||||
|
|
5
docs/source/platypush/events/entities.rst
Normal file
5
docs/source/platypush/events/entities.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
``entities``
|
||||
============
|
||||
|
||||
.. automodule:: platypush.message.event.entities
|
||||
:members:
|
5
docs/source/platypush/plugins/entities.rst
Normal file
5
docs/source/platypush/plugins/entities.rst
Normal file
|
@ -0,0 +1,5 @@
|
|||
``entities``
|
||||
============
|
||||
|
||||
.. automodule:: platypush.plugins.entities
|
||||
:members:
|
|
@ -32,6 +32,7 @@ Plugins
|
|||
platypush/plugins/db.rst
|
||||
platypush/plugins/dbus.rst
|
||||
platypush/plugins/dropbox.rst
|
||||
platypush/plugins/entities.rst
|
||||
platypush/plugins/esp.rst
|
||||
platypush/plugins/ffmpeg.rst
|
||||
platypush/plugins/file.rst
|
||||
|
|
|
@ -9,11 +9,13 @@ import argparse
|
|||
import logging
|
||||
import os
|
||||
import sys
|
||||
from typing import Optional
|
||||
|
||||
from .bus.redis import RedisBus
|
||||
from .config import Config
|
||||
from .context import register_backends, register_plugins
|
||||
from .cron.scheduler import CronScheduler
|
||||
from .entities import init_entities_engine, EntitiesEngine
|
||||
from .event.processor import EventProcessor
|
||||
from .logger import Logger
|
||||
from .message.event import Event
|
||||
|
@ -96,6 +98,7 @@ class Daemon:
|
|||
self.no_capture_stdout = no_capture_stdout
|
||||
self.no_capture_stderr = no_capture_stderr
|
||||
self.event_processor = EventProcessor()
|
||||
self.entities_engine: Optional[EntitiesEngine] = None
|
||||
self.requests_to_process = requests_to_process
|
||||
self.processed_requests = 0
|
||||
self.cron_scheduler = None
|
||||
|
@ -199,6 +202,7 @@ class Daemon:
|
|||
"""Stops the backends and the bus"""
|
||||
from .plugins import RunnablePlugin
|
||||
|
||||
if self.backends:
|
||||
for backend in self.backends.values():
|
||||
backend.stop()
|
||||
|
||||
|
@ -206,9 +210,17 @@ class Daemon:
|
|||
if isinstance(plugin, RunnablePlugin):
|
||||
plugin.stop()
|
||||
|
||||
if self.bus:
|
||||
self.bus.stop()
|
||||
self.bus = None
|
||||
|
||||
if self.cron_scheduler:
|
||||
self.cron_scheduler.stop()
|
||||
self.cron_scheduler = None
|
||||
|
||||
if self.entities_engine:
|
||||
self.entities_engine.stop()
|
||||
self.entities_engine = None
|
||||
|
||||
def run(self):
|
||||
"""Start the daemon"""
|
||||
|
@ -230,6 +242,9 @@ class Daemon:
|
|||
# Initialize the plugins
|
||||
register_plugins(bus=self.bus)
|
||||
|
||||
# Initialize the entities engine
|
||||
self.entities_engine = init_entities_engine()
|
||||
|
||||
# Start the cron scheduler
|
||||
if Config.get_cronjobs():
|
||||
self.cron_scheduler = CronScheduler(jobs=Config.get_cronjobs())
|
||||
|
|
|
@ -3,8 +3,7 @@ import os
|
|||
from typing import Optional, Union, List, Dict, Any
|
||||
|
||||
from sqlalchemy import create_engine, Column, Integer, String, DateTime
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session, declarative_base
|
||||
|
||||
from platypush.backend import Backend
|
||||
from platypush.config import Config
|
||||
|
@ -20,7 +19,7 @@ class Covid19Update(Base):
|
|||
"""Models the Covid19Data table"""
|
||||
|
||||
__tablename__ = 'covid19data'
|
||||
__table_args__ = ({'sqlite_autoincrement': True})
|
||||
__table_args__ = {'sqlite_autoincrement': True}
|
||||
|
||||
country = Column(String, primary_key=True)
|
||||
confirmed = Column(Integer, nullable=False, default=0)
|
||||
|
@ -40,7 +39,12 @@ class Covid19Backend(Backend):
|
|||
"""
|
||||
|
||||
# noinspection PyProtectedMember
|
||||
def __init__(self, country: Optional[Union[str, List[str]]], poll_seconds: Optional[float] = 3600.0, **kwargs):
|
||||
def __init__(
|
||||
self,
|
||||
country: Optional[Union[str, List[str]]],
|
||||
poll_seconds: Optional[float] = 3600.0,
|
||||
**kwargs
|
||||
):
|
||||
"""
|
||||
:param country: Default country (or list of countries) to retrieve the stats for. It can either be the full
|
||||
country name or the country code. Special values:
|
||||
|
@ -56,7 +60,9 @@ class Covid19Backend(Backend):
|
|||
super().__init__(poll_seconds=poll_seconds, **kwargs)
|
||||
self._plugin: Covid19Plugin = get_plugin('covid19')
|
||||
self.country: List[str] = self._plugin._get_countries(country)
|
||||
self.workdir = os.path.join(os.path.expanduser(Config.get('workdir')), 'covid19')
|
||||
self.workdir = os.path.join(
|
||||
os.path.expanduser(Config.get('workdir')), 'covid19'
|
||||
)
|
||||
self.dbfile = os.path.join(self.workdir, 'data.db')
|
||||
os.makedirs(self.workdir, exist_ok=True)
|
||||
|
||||
|
@ -67,22 +73,30 @@ class Covid19Backend(Backend):
|
|||
self.logger.info('Stopped Covid19 backend')
|
||||
|
||||
def _process_update(self, summary: Dict[str, Any], session: Session):
|
||||
update_time = datetime.datetime.fromisoformat(summary['Date'].replace('Z', '+00:00'))
|
||||
update_time = datetime.datetime.fromisoformat(
|
||||
summary['Date'].replace('Z', '+00:00')
|
||||
)
|
||||
|
||||
self.bus.post(Covid19UpdateEvent(
|
||||
self.bus.post(
|
||||
Covid19UpdateEvent(
|
||||
country=summary['Country'],
|
||||
country_code=summary['CountryCode'],
|
||||
confirmed=summary['TotalConfirmed'],
|
||||
deaths=summary['TotalDeaths'],
|
||||
recovered=summary['TotalRecovered'],
|
||||
update_time=update_time,
|
||||
))
|
||||
)
|
||||
)
|
||||
|
||||
session.merge(Covid19Update(country=summary['CountryCode'],
|
||||
session.merge(
|
||||
Covid19Update(
|
||||
country=summary['CountryCode'],
|
||||
confirmed=summary['TotalConfirmed'],
|
||||
deaths=summary['TotalDeaths'],
|
||||
recovered=summary['TotalRecovered'],
|
||||
last_updated_at=update_time))
|
||||
last_updated_at=update_time,
|
||||
)
|
||||
)
|
||||
|
||||
def loop(self):
|
||||
# noinspection PyUnresolvedReferences
|
||||
|
@ -90,23 +104,30 @@ class Covid19Backend(Backend):
|
|||
if not summaries:
|
||||
return
|
||||
|
||||
engine = create_engine('sqlite:///{}'.format(self.dbfile), connect_args={'check_same_thread': False})
|
||||
engine = create_engine(
|
||||
'sqlite:///{}'.format(self.dbfile),
|
||||
connect_args={'check_same_thread': False},
|
||||
)
|
||||
Base.metadata.create_all(engine)
|
||||
Session.configure(bind=engine)
|
||||
session = Session()
|
||||
|
||||
last_records = {
|
||||
record.country: record
|
||||
for record in session.query(Covid19Update).filter(Covid19Update.country.in_(self.country)).all()
|
||||
for record in session.query(Covid19Update)
|
||||
.filter(Covid19Update.country.in_(self.country))
|
||||
.all()
|
||||
}
|
||||
|
||||
for summary in summaries:
|
||||
country = summary['CountryCode']
|
||||
last_record = last_records.get(country)
|
||||
if not last_record or \
|
||||
summary['TotalConfirmed'] != last_record.confirmed or \
|
||||
summary['TotalDeaths'] != last_record.deaths or \
|
||||
summary['TotalRecovered'] != last_record.recovered:
|
||||
if (
|
||||
not last_record
|
||||
or summary['TotalConfirmed'] != last_record.confirmed
|
||||
or summary['TotalDeaths'] != last_record.deaths
|
||||
or summary['TotalRecovered'] != last_record.recovered
|
||||
):
|
||||
self._process_update(summary=summary, session=session)
|
||||
|
||||
session.commit()
|
||||
|
|
|
@ -6,15 +6,28 @@ from typing import Optional, List
|
|||
|
||||
import requests
|
||||
from sqlalchemy import create_engine, Column, String, DateTime
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session, declarative_base
|
||||
|
||||
from platypush.backend import Backend
|
||||
from platypush.config import Config
|
||||
from platypush.message.event.github import GithubPushEvent, GithubCommitCommentEvent, GithubCreateEvent, \
|
||||
GithubDeleteEvent, GithubEvent, GithubForkEvent, GithubWikiEvent, GithubIssueCommentEvent, GithubIssueEvent, \
|
||||
GithubMemberEvent, GithubPublicEvent, GithubPullRequestEvent, GithubPullRequestReviewCommentEvent, \
|
||||
GithubReleaseEvent, GithubSponsorshipEvent, GithubWatchEvent
|
||||
from platypush.message.event.github import (
|
||||
GithubPushEvent,
|
||||
GithubCommitCommentEvent,
|
||||
GithubCreateEvent,
|
||||
GithubDeleteEvent,
|
||||
GithubEvent,
|
||||
GithubForkEvent,
|
||||
GithubWikiEvent,
|
||||
GithubIssueCommentEvent,
|
||||
GithubIssueEvent,
|
||||
GithubMemberEvent,
|
||||
GithubPublicEvent,
|
||||
GithubPullRequestEvent,
|
||||
GithubPullRequestReviewCommentEvent,
|
||||
GithubReleaseEvent,
|
||||
GithubSponsorshipEvent,
|
||||
GithubWatchEvent,
|
||||
)
|
||||
|
||||
Base = declarative_base()
|
||||
Session = scoped_session(sessionmaker())
|
||||
|
@ -71,8 +84,17 @@ class GithubBackend(Backend):
|
|||
|
||||
_base_url = 'https://api.github.com'
|
||||
|
||||
def __init__(self, user: str, user_token: str, repos: Optional[List[str]] = None, org: Optional[str] = None,
|
||||
poll_seconds: int = 60, max_events_per_scan: Optional[int] = 10, *args, **kwargs):
|
||||
def __init__(
|
||||
self,
|
||||
user: str,
|
||||
user_token: str,
|
||||
repos: Optional[List[str]] = None,
|
||||
org: Optional[str] = None,
|
||||
poll_seconds: int = 60,
|
||||
max_events_per_scan: Optional[int] = 10,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
"""
|
||||
If neither ``repos`` nor ``org`` is specified then the backend will monitor all new events on user level.
|
||||
|
||||
|
@ -102,11 +124,17 @@ class GithubBackend(Backend):
|
|||
|
||||
def _request(self, uri: str, method: str = 'get') -> dict:
|
||||
method = getattr(requests, method.lower())
|
||||
return method(self._base_url + uri, auth=(self.user, self.user_token),
|
||||
headers={'Accept': 'application/vnd.github.v3+json'}).json()
|
||||
return method(
|
||||
self._base_url + uri,
|
||||
auth=(self.user, self.user_token),
|
||||
headers={'Accept': 'application/vnd.github.v3+json'},
|
||||
).json()
|
||||
|
||||
def _init_db(self):
|
||||
engine = create_engine('sqlite:///{}'.format(self.dbfile), connect_args={'check_same_thread': False})
|
||||
engine = create_engine(
|
||||
'sqlite:///{}'.format(self.dbfile),
|
||||
connect_args={'check_same_thread': False},
|
||||
)
|
||||
Base.metadata.create_all(engine)
|
||||
Session.configure(bind=engine)
|
||||
|
||||
|
@ -128,7 +156,11 @@ class GithubBackend(Backend):
|
|||
def _get_last_event_time(self, uri: str):
|
||||
with self.db_lock:
|
||||
record = self._get_or_create_resource(uri=uri, session=Session())
|
||||
return record.last_updated_at.replace(tzinfo=datetime.timezone.utc) if record.last_updated_at else None
|
||||
return (
|
||||
record.last_updated_at.replace(tzinfo=datetime.timezone.utc)
|
||||
if record.last_updated_at
|
||||
else None
|
||||
)
|
||||
|
||||
def _update_last_event_time(self, uri: str, last_updated_at: datetime.datetime):
|
||||
with self.db_lock:
|
||||
|
@ -158,9 +190,18 @@ class GithubBackend(Backend):
|
|||
'WatchEvent': GithubWatchEvent,
|
||||
}
|
||||
|
||||
event_type = event_mapping[event['type']] if event['type'] in event_mapping else GithubEvent
|
||||
return event_type(event_type=event['type'], actor=event['actor'], repo=event.get('repo', {}),
|
||||
payload=event['payload'], created_at=cls._to_datetime(event['created_at']))
|
||||
event_type = (
|
||||
event_mapping[event['type']]
|
||||
if event['type'] in event_mapping
|
||||
else GithubEvent
|
||||
)
|
||||
return event_type(
|
||||
event_type=event['type'],
|
||||
actor=event['actor'],
|
||||
repo=event.get('repo', {}),
|
||||
payload=event['payload'],
|
||||
created_at=cls._to_datetime(event['created_at']),
|
||||
)
|
||||
|
||||
def _events_monitor(self, uri: str, method: str = 'get'):
|
||||
def thread():
|
||||
|
@ -175,7 +216,10 @@ class GithubBackend(Backend):
|
|||
fired_events = []
|
||||
|
||||
for event in events:
|
||||
if self.max_events_per_scan and len(fired_events) >= self.max_events_per_scan:
|
||||
if (
|
||||
self.max_events_per_scan
|
||||
and len(fired_events) >= self.max_events_per_scan
|
||||
):
|
||||
break
|
||||
|
||||
event_time = self._to_datetime(event['created_at'])
|
||||
|
@ -189,12 +233,17 @@ class GithubBackend(Backend):
|
|||
for event in fired_events:
|
||||
self.bus.post(event)
|
||||
|
||||
self._update_last_event_time(uri=uri, last_updated_at=new_last_event_time)
|
||||
self._update_last_event_time(
|
||||
uri=uri, last_updated_at=new_last_event_time
|
||||
)
|
||||
except Exception as e:
|
||||
self.logger.warning('Encountered exception while fetching events from {}: {}'.format(
|
||||
uri, str(e)))
|
||||
self.logger.warning(
|
||||
'Encountered exception while fetching events from {}: {}'.format(
|
||||
uri, str(e)
|
||||
)
|
||||
)
|
||||
self.logger.exception(e)
|
||||
finally:
|
||||
|
||||
if self.wait_stop(timeout=self.poll_seconds):
|
||||
break
|
||||
|
||||
|
@ -206,12 +255,30 @@ class GithubBackend(Backend):
|
|||
|
||||
if self.repos:
|
||||
for repo in self.repos:
|
||||
monitors.append(threading.Thread(target=self._events_monitor('/networks/{repo}/events'.format(repo=repo))))
|
||||
monitors.append(
|
||||
threading.Thread(
|
||||
target=self._events_monitor(
|
||||
'/networks/{repo}/events'.format(repo=repo)
|
||||
)
|
||||
)
|
||||
)
|
||||
if self.org:
|
||||
monitors.append(threading.Thread(target=self._events_monitor('/orgs/{org}/events'.format(org=self.org))))
|
||||
monitors.append(
|
||||
threading.Thread(
|
||||
target=self._events_monitor(
|
||||
'/orgs/{org}/events'.format(org=self.org)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
if not (self.repos or self.org):
|
||||
monitors.append(threading.Thread(target=self._events_monitor('/users/{user}/events'.format(user=self.user))))
|
||||
monitors.append(
|
||||
threading.Thread(
|
||||
target=self._events_monitor(
|
||||
'/users/{user}/events'.format(user=self.user)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
for monitor in monitors:
|
||||
monitor.start()
|
||||
|
@ -222,4 +289,5 @@ class GithubBackend(Backend):
|
|||
|
||||
self.logger.info('Github backend terminated')
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import json
|
||||
|
||||
from flask import Blueprint, abort, request, Response
|
||||
from flask import Blueprint, abort, request
|
||||
from flask.wrappers import Response
|
||||
|
||||
from platypush.backend.http.app import template_folder
|
||||
from platypush.backend.http.app.utils import authenticate, logger, send_message
|
||||
|
@ -14,8 +15,8 @@ __routes__ = [
|
|||
|
||||
|
||||
@execute.route('/execute', methods=['POST'])
|
||||
@authenticate()
|
||||
def execute():
|
||||
@authenticate(json=True)
|
||||
def execute_route():
|
||||
"""Endpoint to execute commands"""
|
||||
try:
|
||||
msg = json.loads(request.data.decode('utf-8'))
|
||||
|
|
|
@ -8,16 +8,21 @@ from platypush.backend.http.app import template_folder
|
|||
|
||||
|
||||
img_folder = os.path.join(template_folder, 'img')
|
||||
fonts_folder = os.path.join(template_folder, 'fonts')
|
||||
icons_folder = os.path.join(template_folder, 'icons')
|
||||
resources = Blueprint('resources', __name__, template_folder=template_folder)
|
||||
favicon = Blueprint('favicon', __name__, template_folder=template_folder)
|
||||
img = Blueprint('img', __name__, template_folder=template_folder)
|
||||
icons = Blueprint('icons', __name__, template_folder=template_folder)
|
||||
fonts = Blueprint('fonts', __name__, template_folder=template_folder)
|
||||
|
||||
# Declare routes list
|
||||
__routes__ = [
|
||||
resources,
|
||||
favicon,
|
||||
img,
|
||||
icons,
|
||||
fonts,
|
||||
]
|
||||
|
||||
|
||||
|
@ -42,9 +47,11 @@ def resources_path(path):
|
|||
real_path = real_base_path
|
||||
|
||||
file_path = [
|
||||
s for s in re.sub(
|
||||
s
|
||||
for s in re.sub(
|
||||
r'^{}(.*)$'.format(base_path), '\\1', path # lgtm [py/regex-injection]
|
||||
).split('/') if s
|
||||
).split('/')
|
||||
if s
|
||||
]
|
||||
|
||||
for p in file_path[:-1]:
|
||||
|
@ -71,10 +78,16 @@ def imgpath(path):
|
|||
return send_from_directory(img_folder, path)
|
||||
|
||||
|
||||
@img.route('/icons/<path:path>', methods=['GET'])
|
||||
@icons.route('/icons/<path:path>', methods=['GET'])
|
||||
def iconpath(path):
|
||||
"""Default static icons"""
|
||||
return send_from_directory(icons_folder, path)
|
||||
|
||||
|
||||
@fonts.route('/fonts/<path:path>', methods=['GET'])
|
||||
def fontpath(path):
|
||||
"""Default fonts"""
|
||||
return send_from_directory(fonts_folder, path)
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
|
@ -3,7 +3,8 @@ import logging
|
|||
import os
|
||||
|
||||
from functools import wraps
|
||||
from flask import abort, request, redirect, Response, current_app
|
||||
from flask import abort, request, redirect, jsonify, current_app
|
||||
from flask.wrappers import Response
|
||||
from redis import Redis
|
||||
|
||||
# NOTE: The HTTP service will *only* work on top of a Redis bus. The default
|
||||
|
@ -184,7 +185,37 @@ def _authenticate_csrf_token():
|
|||
)
|
||||
|
||||
|
||||
def authenticate(redirect_page='', skip_auth_methods=None, check_csrf_token=False):
|
||||
def authenticate(
|
||||
redirect_page='',
|
||||
skip_auth_methods=None,
|
||||
check_csrf_token=False,
|
||||
json=False,
|
||||
):
|
||||
def on_auth_fail(has_users=True):
|
||||
if json:
|
||||
if has_users:
|
||||
return (
|
||||
jsonify(
|
||||
{
|
||||
'message': 'Not logged in',
|
||||
}
|
||||
),
|
||||
401,
|
||||
)
|
||||
|
||||
return (
|
||||
jsonify(
|
||||
{
|
||||
'message': 'Please register a user through '
|
||||
'the web panel first',
|
||||
}
|
||||
),
|
||||
412,
|
||||
)
|
||||
|
||||
target_page = 'login' if has_users else 'register'
|
||||
return redirect(f'/{target_page}?redirect={redirect_page or request.url}', 307)
|
||||
|
||||
def decorator(f):
|
||||
@wraps(f)
|
||||
def wrapper(*args, **kwargs):
|
||||
|
@ -213,9 +244,7 @@ def authenticate(redirect_page='', skip_auth_methods=None, check_csrf_token=Fals
|
|||
if session_auth_ok:
|
||||
return f(*args, **kwargs)
|
||||
|
||||
return redirect(
|
||||
'/login?redirect=' + (redirect_page or request.url), 307
|
||||
)
|
||||
return on_auth_fail()
|
||||
|
||||
# CSRF token check
|
||||
if check_csrf_token:
|
||||
|
@ -224,9 +253,7 @@ def authenticate(redirect_page='', skip_auth_methods=None, check_csrf_token=Fals
|
|||
return abort(403, 'Invalid or missing csrf_token')
|
||||
|
||||
if n_users == 0 and 'session' not in skip_methods:
|
||||
return redirect(
|
||||
'/register?redirect=' + (redirect_page or request.url), 307
|
||||
)
|
||||
return on_auth_fail(has_users=False)
|
||||
|
||||
if (
|
||||
('http' not in skip_methods and http_auth_ok)
|
||||
|
|
|
@ -2,11 +2,17 @@ import datetime
|
|||
import enum
|
||||
import os
|
||||
|
||||
from sqlalchemy import create_engine, Column, Integer, String, DateTime, \
|
||||
Enum, ForeignKey
|
||||
from sqlalchemy import (
|
||||
create_engine,
|
||||
Column,
|
||||
Integer,
|
||||
String,
|
||||
DateTime,
|
||||
Enum,
|
||||
ForeignKey,
|
||||
)
|
||||
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session, declarative_base
|
||||
from sqlalchemy.sql.expression import func
|
||||
|
||||
from platypush.backend.http.request import HttpRequest
|
||||
|
@ -44,18 +50,31 @@ class RssUpdates(HttpRequest):
|
|||
|
||||
"""
|
||||
|
||||
user_agent = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) ' + \
|
||||
'Chrome/62.0.3202.94 Safari/537.36'
|
||||
user_agent = (
|
||||
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) '
|
||||
+ 'Chrome/62.0.3202.94 Safari/537.36'
|
||||
)
|
||||
|
||||
def __init__(self, url, title=None, headers=None, params=None, max_entries=None,
|
||||
extract_content=False, digest_format=None, user_agent: str = user_agent,
|
||||
body_style: str = 'font-size: 22px; ' +
|
||||
'font-family: "Merriweather", Georgia, "Times New Roman", Times, serif;',
|
||||
def __init__(
|
||||
self,
|
||||
url,
|
||||
title=None,
|
||||
headers=None,
|
||||
params=None,
|
||||
max_entries=None,
|
||||
extract_content=False,
|
||||
digest_format=None,
|
||||
user_agent: str = user_agent,
|
||||
body_style: str = 'font-size: 22px; '
|
||||
+ 'font-family: "Merriweather", Georgia, "Times New Roman", Times, serif;',
|
||||
title_style: str = 'margin-top: 30px',
|
||||
subtitle_style: str = 'margin-top: 10px; page-break-after: always',
|
||||
article_title_style: str = 'page-break-before: always',
|
||||
article_link_style: str = 'color: #555; text-decoration: none; border-bottom: 1px dotted',
|
||||
article_content_style: str = '', *argv, **kwargs):
|
||||
article_content_style: str = '',
|
||||
*argv,
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
:param url: URL to the RSS feed to be monitored.
|
||||
:param title: Optional title for the feed.
|
||||
|
@ -91,7 +110,9 @@ class RssUpdates(HttpRequest):
|
|||
# If true, then the http.webpage plugin will be used to parse the content
|
||||
self.extract_content = extract_content
|
||||
|
||||
self.digest_format = digest_format.lower() if digest_format else None # Supported formats: html, pdf
|
||||
self.digest_format = (
|
||||
digest_format.lower() if digest_format else None
|
||||
) # Supported formats: html, pdf
|
||||
|
||||
os.makedirs(os.path.expanduser(os.path.dirname(self.dbfile)), exist_ok=True)
|
||||
|
||||
|
@ -119,7 +140,11 @@ class RssUpdates(HttpRequest):
|
|||
|
||||
@staticmethod
|
||||
def _get_latest_update(session, source_id):
|
||||
return session.query(func.max(FeedEntry.published)).filter_by(source_id=source_id).scalar()
|
||||
return (
|
||||
session.query(func.max(FeedEntry.published))
|
||||
.filter_by(source_id=source_id)
|
||||
.scalar()
|
||||
)
|
||||
|
||||
def _parse_entry_content(self, link):
|
||||
self.logger.info('Extracting content from {}'.format(link))
|
||||
|
@ -130,14 +155,20 @@ class RssUpdates(HttpRequest):
|
|||
errors = response.errors
|
||||
|
||||
if not output:
|
||||
self.logger.warning('Mercury parser error: {}'.format(errors or '[unknown error]'))
|
||||
self.logger.warning(
|
||||
'Mercury parser error: {}'.format(errors or '[unknown error]')
|
||||
)
|
||||
return
|
||||
|
||||
return output.get('content')
|
||||
|
||||
def get_new_items(self, response):
|
||||
import feedparser
|
||||
engine = create_engine('sqlite:///{}'.format(self.dbfile), connect_args={'check_same_thread': False})
|
||||
|
||||
engine = create_engine(
|
||||
'sqlite:///{}'.format(self.dbfile),
|
||||
connect_args={'check_same_thread': False},
|
||||
)
|
||||
|
||||
Base.metadata.create_all(engine)
|
||||
Session.configure(bind=engine)
|
||||
|
@ -157,12 +188,16 @@ class RssUpdates(HttpRequest):
|
|||
|
||||
content = u'''
|
||||
<h1 style="{title_style}">{title}</h1>
|
||||
<h2 style="{subtitle_style}">Feeds digest generated on {creation_date}</h2>'''.\
|
||||
format(title_style=self.title_style, title=self.title, subtitle_style=self.subtitle_style,
|
||||
creation_date=datetime.datetime.now().strftime('%d %B %Y, %H:%M'))
|
||||
<h2 style="{subtitle_style}">Feeds digest generated on {creation_date}</h2>'''.format(
|
||||
title_style=self.title_style,
|
||||
title=self.title,
|
||||
subtitle_style=self.subtitle_style,
|
||||
creation_date=datetime.datetime.now().strftime('%d %B %Y, %H:%M'),
|
||||
)
|
||||
|
||||
self.logger.info('Parsed {:d} items from RSS feed <{}>'
|
||||
.format(len(feed.entries), self.url))
|
||||
self.logger.info(
|
||||
'Parsed {:d} items from RSS feed <{}>'.format(len(feed.entries), self.url)
|
||||
)
|
||||
|
||||
for entry in feed.entries:
|
||||
if not entry.published_parsed:
|
||||
|
@ -171,9 +206,10 @@ class RssUpdates(HttpRequest):
|
|||
try:
|
||||
entry_timestamp = datetime.datetime(*entry.published_parsed[:6])
|
||||
|
||||
if latest_update is None \
|
||||
or entry_timestamp > latest_update:
|
||||
self.logger.info('Processed new item from RSS feed <{}>'.format(self.url))
|
||||
if latest_update is None or entry_timestamp > latest_update:
|
||||
self.logger.info(
|
||||
'Processed new item from RSS feed <{}>'.format(self.url)
|
||||
)
|
||||
entry.summary = entry.summary if hasattr(entry, 'summary') else None
|
||||
|
||||
if self.extract_content:
|
||||
|
@ -188,9 +224,13 @@ class RssUpdates(HttpRequest):
|
|||
<a href="{link}" target="_blank" style="{article_link_style}">{title}</a>
|
||||
</h1>
|
||||
<div class="_parsed-content" style="{article_content_style}">{content}</div>'''.format(
|
||||
article_title_style=self.article_title_style, article_link_style=self.article_link_style,
|
||||
article_content_style=self.article_content_style, link=entry.link, title=entry.title,
|
||||
content=entry.content)
|
||||
article_title_style=self.article_title_style,
|
||||
article_link_style=self.article_link_style,
|
||||
article_content_style=self.article_content_style,
|
||||
link=entry.link,
|
||||
title=entry.title,
|
||||
content=entry.content,
|
||||
)
|
||||
|
||||
e = {
|
||||
'entry_id': entry.id,
|
||||
|
@ -207,21 +247,32 @@ class RssUpdates(HttpRequest):
|
|||
if self.max_entries and len(entries) > self.max_entries:
|
||||
break
|
||||
except Exception as e:
|
||||
self.logger.warning('Exception encountered while parsing RSS ' +
|
||||
'RSS feed {}: {}'.format(entry.link, str(e)))
|
||||
self.logger.warning(
|
||||
'Exception encountered while parsing RSS '
|
||||
+ f'RSS feed {entry.link}: {e}'
|
||||
)
|
||||
self.logger.exception(e)
|
||||
|
||||
source_record.last_updated_at = parse_start_time
|
||||
digest_filename = None
|
||||
|
||||
if entries:
|
||||
self.logger.info('Parsed {} new entries from the RSS feed {}'.format(
|
||||
len(entries), self.title))
|
||||
self.logger.info(
|
||||
'Parsed {} new entries from the RSS feed {}'.format(
|
||||
len(entries), self.title
|
||||
)
|
||||
)
|
||||
|
||||
if self.digest_format:
|
||||
digest_filename = os.path.join(self.workdir, 'cache', '{}_{}.{}'.format(
|
||||
digest_filename = os.path.join(
|
||||
self.workdir,
|
||||
'cache',
|
||||
'{}_{}.{}'.format(
|
||||
datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S'),
|
||||
self.title, self.digest_format))
|
||||
self.title,
|
||||
self.digest_format,
|
||||
),
|
||||
)
|
||||
|
||||
os.makedirs(os.path.dirname(digest_filename), exist_ok=True)
|
||||
|
||||
|
@ -233,12 +284,15 @@ class RssUpdates(HttpRequest):
|
|||
</head>
|
||||
<body style="{body_style}">{content}</body>
|
||||
</html>
|
||||
'''.format(title=self.title, body_style=self.body_style, content=content)
|
||||
'''.format(
|
||||
title=self.title, body_style=self.body_style, content=content
|
||||
)
|
||||
|
||||
with open(digest_filename, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
elif self.digest_format == 'pdf':
|
||||
from weasyprint import HTML, CSS
|
||||
|
||||
try:
|
||||
from weasyprint.fonts import FontConfiguration
|
||||
except ImportError:
|
||||
|
@ -246,37 +300,47 @@ class RssUpdates(HttpRequest):
|
|||
|
||||
body_style = 'body { ' + self.body_style + ' }'
|
||||
font_config = FontConfiguration()
|
||||
css = [CSS('https://fonts.googleapis.com/css?family=Merriweather'),
|
||||
CSS(string=body_style, font_config=font_config)]
|
||||
css = [
|
||||
CSS('https://fonts.googleapis.com/css?family=Merriweather'),
|
||||
CSS(string=body_style, font_config=font_config),
|
||||
]
|
||||
|
||||
HTML(string=content).write_pdf(digest_filename, stylesheets=css)
|
||||
else:
|
||||
raise RuntimeError('Unsupported format: {}. Supported formats: ' +
|
||||
'html or pdf'.format(self.digest_format))
|
||||
raise RuntimeError(
|
||||
f'Unsupported format: {self.digest_format}. Supported formats: html, pdf'
|
||||
)
|
||||
|
||||
digest_entry = FeedDigest(source_id=source_record.id,
|
||||
digest_entry = FeedDigest(
|
||||
source_id=source_record.id,
|
||||
format=self.digest_format,
|
||||
filename=digest_filename)
|
||||
filename=digest_filename,
|
||||
)
|
||||
|
||||
session.add(digest_entry)
|
||||
self.logger.info('{} digest ready: {}'.format(self.digest_format, digest_filename))
|
||||
self.logger.info(
|
||||
'{} digest ready: {}'.format(self.digest_format, digest_filename)
|
||||
)
|
||||
|
||||
session.commit()
|
||||
self.logger.info('Parsing RSS feed {}: completed'.format(self.title))
|
||||
|
||||
return NewFeedEvent(request=dict(self), response=entries,
|
||||
return NewFeedEvent(
|
||||
request=dict(self),
|
||||
response=entries,
|
||||
source_id=source_record.id,
|
||||
source_title=source_record.title,
|
||||
title=self.title,
|
||||
digest_format=self.digest_format,
|
||||
digest_filename=digest_filename)
|
||||
digest_filename=digest_filename,
|
||||
)
|
||||
|
||||
|
||||
class FeedSource(Base):
|
||||
"""Models the FeedSource table, containing RSS sources to be parsed"""
|
||||
|
||||
__tablename__ = 'FeedSource'
|
||||
__table_args__ = ({'sqlite_autoincrement': True})
|
||||
__table_args__ = {'sqlite_autoincrement': True}
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
title = Column(String)
|
||||
|
@ -288,7 +352,7 @@ class FeedEntry(Base):
|
|||
"""Models the FeedEntry table, which contains RSS entries"""
|
||||
|
||||
__tablename__ = 'FeedEntry'
|
||||
__table_args__ = ({'sqlite_autoincrement': True})
|
||||
__table_args__ = {'sqlite_autoincrement': True}
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
entry_id = Column(String)
|
||||
|
@ -309,7 +373,7 @@ class FeedDigest(Base):
|
|||
pdf = 2
|
||||
|
||||
__tablename__ = 'FeedDigest'
|
||||
__table_args__ = ({'sqlite_autoincrement': True})
|
||||
__table_args__ = {'sqlite_autoincrement': True}
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
source_id = Column(Integer, ForeignKey('FeedSource.id'), nullable=False)
|
||||
|
@ -317,4 +381,5 @@ class FeedDigest(Base):
|
|||
filename = Column(String, nullable=False)
|
||||
created_at = Column(DateTime, nullable=False, default=datetime.datetime.utcnow)
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
|
BIN
platypush/backend/http/webapp/dist/fonts/Poppins.ttf
vendored
Normal file
BIN
platypush/backend/http/webapp/dist/fonts/Poppins.ttf
vendored
Normal file
Binary file not shown.
7
platypush/backend/http/webapp/dist/fonts/poppins.css
vendored
Normal file
7
platypush/backend/http/webapp/dist/fonts/poppins.css
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
@font-face {
|
||||
font-family: 'Poppins';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(./Poppins.ttf) format('truetype');
|
||||
}
|
BIN
platypush/backend/http/webapp/dist/icons/smartthings.png
vendored
Normal file
BIN
platypush/backend/http/webapp/dist/icons/smartthings.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 4 KiB |
BIN
platypush/backend/http/webapp/dist/img/logo.png
vendored
Normal file
BIN
platypush/backend/http/webapp/dist/img/logo.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
BIN
platypush/backend/http/webapp/dist/img/spinner.gif
vendored
Normal file
BIN
platypush/backend/http/webapp/dist/img/spinner.gif
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
|
@ -1 +1 @@
|
|||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>platypush</title><script defer="defer" type="module" src="/static/js/chunk-vendors.5adf1720.js"></script><script defer="defer" type="module" src="/static/js/app.12b17001.js"></script><link href="/static/css/chunk-vendors.5cf89a0c.css" rel="stylesheet"><link href="/static/css/app.5028a669.css" rel="stylesheet"><script defer="defer" src="/static/js/chunk-vendors-legacy.6835b8d0.js" nomodule></script><script defer="defer" src="/static/js/app-legacy.ab28664f.js" nomodule></script></head><body><noscript><strong>We're sorry but platypush doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><link rel="stylesheet" href="/fonts/poppins.css"><title>platypush</title><script defer="defer" type="module" src="/static/js/chunk-vendors.95bedba1.js"></script><script defer="defer" type="module" src="/static/js/app.0ecd5641.js"></script><link href="/static/css/chunk-vendors.0fcd36f0.css" rel="stylesheet"><link href="/static/css/app.3b5b9cec.css" rel="stylesheet"><script defer="defer" src="/static/js/chunk-vendors-legacy.c27e0a41.js" nomodule></script><script defer="defer" src="/static/js/app-legacy.602f8c67.js" nomodule></script></head><body><noscript><strong>We're sorry but platypush doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
1
platypush/backend/http/webapp/dist/static/css/1155.3c072b53.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/1155.3c072b53.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/1406.3c45f7ef.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/1406.3c45f7ef.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/2107.3a08bbb5.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/2107.3a08bbb5.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/2790.8a938bab.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/2790.8a938bab.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/3490.3516cb6e.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/3490.3516cb6e.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/4196.f1fcf8f5.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/4196.f1fcf8f5.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/4658.0aa0c9b4.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/4658.0aa0c9b4.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/4848.ae3af6a6.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/4848.ae3af6a6.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/4981.8830c3ce.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/4981.8830c3ce.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/518.44f63b6e.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/518.44f63b6e.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/5779.b285a776.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/5779.b285a776.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/5810.0aa0c9b4.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/5810.0aa0c9b4.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/5824.f9f7ad29.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/5824.f9f7ad29.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/6162.f3d46bda.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/6162.f3d46bda.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/65.d6cbc229.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/65.d6cbc229.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/6833.c53bec53.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/6833.c53bec53.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/6899.f3d46bda.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/6899.f3d46bda.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/7029.13387da1.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/7029.13387da1.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/747.3c45f7ef.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/747.3c45f7ef.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/7643.e25374a8.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/7643.e25374a8.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/8729.f98d84da.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/8729.f98d84da.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/9892.68b29dbb.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/9892.68b29dbb.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/css/9978.13387da1.css
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/css/9978.13387da1.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
17
platypush/backend/http/webapp/dist/static/css/app.3b5b9cec.css
vendored
Normal file
17
platypush/backend/http/webapp/dist/static/css/app.3b5b9cec.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
platypush/backend/http/webapp/dist/static/img/logo.5b906db6.png
vendored
Normal file
BIN
platypush/backend/http/webapp/dist/static/img/logo.5b906db6.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
BIN
platypush/backend/http/webapp/dist/static/img/spinner.c0bee445.gif
vendored
Normal file
BIN
platypush/backend/http/webapp/dist/static/img/spinner.c0bee445.gif
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
2
platypush/backend/http/webapp/dist/static/js/1155-legacy.3b386edd.js
vendored
Normal file
2
platypush/backend/http/webapp/dist/static/js/1155-legacy.3b386edd.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/js/1155-legacy.3b386edd.js.map
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/js/1155-legacy.3b386edd.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2
platypush/backend/http/webapp/dist/static/js/1155.ae99e2b9.js
vendored
Normal file
2
platypush/backend/http/webapp/dist/static/js/1155.ae99e2b9.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/js/1155.ae99e2b9.js.map
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/js/1155.ae99e2b9.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
platypush/backend/http/webapp/dist/static/js/1406-legacy.49afea8a.js
vendored
Normal file
2
platypush/backend/http/webapp/dist/static/js/1406-legacy.49afea8a.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
platypush/backend/http/webapp/dist/static/js/1406-legacy.49afea8a.js.map
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/js/1406-legacy.49afea8a.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -1,2 +1,2 @@
|
|||
"use strict";(self["webpackChunkplatypush"]=self["webpackChunkplatypush"]||[]).push([[1595],{1595:function(e,t,n){n.r(t),n.d(t,{default:function(){return f}});var s=n(6252),o=n(3577),i={class:"date-time"},a=["textContent"],r=["textContent"];function u(e,t,n,u,h,w){return(0,s.wg)(),(0,s.iD)("div",i,[w._showDate?((0,s.wg)(),(0,s.iD)("div",{key:0,class:"date",textContent:(0,o.zw)(e.formatDate(e.now))},null,8,a)):(0,s.kq)("",!0),w._showTime?((0,s.wg)(),(0,s.iD)("div",{key:1,class:"time",textContent:(0,o.zw)(e.formatTime(e.now,w._showSeconds))},null,8,r)):(0,s.kq)("",!0)])}var h=n(2628),w={name:"DateTime",mixins:[h.Z],props:{showDate:{required:!1,default:!0},showTime:{required:!1,default:!0},showSeconds:{required:!1,default:!0}},computed:{_showTime:function(){return this.parseBoolean(this.showTime)},_showDate:function(){return this.parseBoolean(this.showDate)},_showSeconds:function(){return this.parseBoolean(this.showSeconds)}},data:function(){return{now:new Date}},methods:{refreshTime:function(){this.now=new Date}},mounted:function(){this.refreshTime(),setInterval(this.refreshTime,1e3)}},c=n(3744);const d=(0,c.Z)(w,[["render",u],["__scopeId","data-v-ca42eb9c"]]);var f=d}}]);
|
||||
//# sourceMappingURL=1595-legacy.ddcdc704.js.map
|
||||
"use strict";(self["webpackChunkplatypush"]=self["webpackChunkplatypush"]||[]).push([[1595],{1595:function(e,t,n){n.r(t),n.d(t,{default:function(){return f}});var s=n(6252),o=n(3577),i={class:"date-time"},a=["textContent"],r=["textContent"];function u(e,t,n,u,h,w){return(0,s.wg)(),(0,s.iD)("div",i,[w._showDate?((0,s.wg)(),(0,s.iD)("div",{key:0,class:"date",textContent:(0,o.zw)(e.formatDate(e.now))},null,8,a)):(0,s.kq)("",!0),w._showTime?((0,s.wg)(),(0,s.iD)("div",{key:1,class:"time",textContent:(0,o.zw)(e.formatTime(e.now,w._showSeconds))},null,8,r)):(0,s.kq)("",!0)])}var h=n(6813),w={name:"DateTime",mixins:[h.Z],props:{showDate:{required:!1,default:!0},showTime:{required:!1,default:!0},showSeconds:{required:!1,default:!0}},computed:{_showTime:function(){return this.parseBoolean(this.showTime)},_showDate:function(){return this.parseBoolean(this.showDate)},_showSeconds:function(){return this.parseBoolean(this.showSeconds)}},data:function(){return{now:new Date}},methods:{refreshTime:function(){this.now=new Date}},mounted:function(){this.refreshTime(),setInterval(this.refreshTime,1e3)}},c=n(3744);const d=(0,c.Z)(w,[["render",u],["__scopeId","data-v-ca42eb9c"]]);var f=d}}]);
|
||||
//# sourceMappingURL=1595-legacy.69aea4ae.js.map
|
1
platypush/backend/http/webapp/dist/static/js/1595-legacy.69aea4ae.js.map
vendored
Normal file
1
platypush/backend/http/webapp/dist/static/js/1595-legacy.69aea4ae.js.map
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"static/js/1595-legacy.69aea4ae.js","mappings":"0LACOA,MAAM,a,8EAAX,QAGM,MAHN,EAGM,CAF6C,EAAAC,YAAA,WAAjD,QAA8D,O,MAAzDD,MAAM,O,aAAO,QAAwB,EAAN,WAAC,EAAAE,OAArC,2BAC+D,EAAAC,YAAA,WAA/D,QAA4E,O,MAAvEH,MAAM,O,aAAO,QAAsC,EAApB,WAAC,EAAAE,IAAK,EAAAE,gBAA1C,4B,eAQJ,GACEC,KAAM,WACNC,OAAQ,CAACC,EAAA,GACTC,MAAO,CAELC,SAAU,CACRC,UAAU,EACVC,SAAS,GAIXC,SAAU,CACRF,UAAU,EACVC,SAAS,GAIXE,YAAa,CACXH,UAAU,EACVC,SAAS,IAIbG,SAAU,CACRX,UADQ,WAEN,OAAOY,KAAKC,aAAaD,KAAKH,SAC/B,EAEDX,UALQ,WAMN,OAAOc,KAAKC,aAAaD,KAAKN,SAC/B,EAEDL,aATQ,WAUN,OAAOW,KAAKC,aAAaD,KAAKF,YAC/B,GAGHI,KAAM,WACJ,MAAO,CACLf,IAAK,IAAIgB,KAEZ,EAEDC,QAAS,CACPC,YADO,WAELL,KAAKb,IAAM,IAAIgB,IAChB,GAGHG,QAAS,WACPN,KAAKK,cACLE,YAAYP,KAAKK,YAAa,IAC/B,G,UCxDH,MAAMG,GAA2B,OAAgB,EAAQ,CAAC,CAAC,SAASC,GAAQ,CAAC,YAAY,qBAEzF,O","sources":["webpack://platypush/./src/components/widgets/DateTime/Index.vue","webpack://platypush/./src/components/widgets/DateTime/Index.vue?dfd6"],"sourcesContent":["<template>\n <div class=\"date-time\">\n <div class=\"date\" v-text=\"formatDate(now)\" v-if=\"_showDate\" />\n <div class=\"time\" v-text=\"formatTime(now, _showSeconds)\" v-if=\"_showTime\" />\n </div>\n</template>\n\n<script>\nimport Utils from \"@/Utils\";\n\n// Widget to show date and time\nexport default {\n name: 'DateTime',\n mixins: [Utils],\n props: {\n // If false then don't display the date.\n showDate: {\n required: false,\n default: true,\n },\n\n // If false then don't display the time.\n showTime: {\n required: false,\n default: true,\n },\n\n // If false then don't display the seconds.\n showSeconds: {\n required: false,\n default: true,\n },\n },\n\n computed: {\n _showTime() {\n return this.parseBoolean(this.showTime)\n },\n\n _showDate() {\n return this.parseBoolean(this.showDate)\n },\n\n _showSeconds() {\n return this.parseBoolean(this.showSeconds)\n },\n },\n\n data: function() {\n return {\n now: new Date(),\n };\n },\n\n methods: {\n refreshTime() {\n this.now = new Date()\n },\n },\n\n mounted: function() {\n this.refreshTime()\n setInterval(this.refreshTime, 1000)\n },\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.date-time {\n .date {\n font-size: 1.3em;\n }\n\n .time {\n font-size: 2em;\n }\n}\n</style>\n","import { render } from \"./Index.vue?vue&type=template&id=ca42eb9c&scoped=true\"\nimport script from \"./Index.vue?vue&type=script&lang=js\"\nexport * from \"./Index.vue?vue&type=script&lang=js\"\n\nimport \"./Index.vue?vue&type=style&index=0&id=ca42eb9c&lang=scss&scoped=true\"\n\nimport exportComponent from \"/home/blacklight/git_tree/platypush/platypush/backend/http/webapp/node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-ca42eb9c\"]])\n\nexport default __exports__"],"names":["class","_showDate","now","_showTime","_showSeconds","name","mixins","Utils","props","showDate","required","default","showTime","showSeconds","computed","this","parseBoolean","data","Date","methods","refreshTime","mounted","setInterval","__exports__","render"],"sourceRoot":""}
|
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"static/js/1595-legacy.ddcdc704.js","mappings":"0LACOA,MAAM,a,8EAAX,QAGM,MAHN,EAGM,CAF6C,EAAAC,YAAA,WAAjD,QAA8D,O,MAAzDD,MAAM,O,aAAO,QAAwB,EAAN,WAAC,EAAAE,OAArC,2BAC+D,EAAAC,YAAA,WAA/D,QAA4E,O,MAAvEH,MAAM,O,aAAO,QAAsC,EAApB,WAAC,EAAAE,IAAK,EAAAE,gBAA1C,6B,cAQJ,GACEC,KAAM,WACNC,OAAQ,CAACC,EAAA,GACTC,MAAO,CAELC,SAAU,CACRC,UAAU,EACVC,SAAS,GAIXC,SAAU,CACRF,UAAU,EACVC,SAAS,GAIXE,YAAa,CACXH,UAAU,EACVC,SAAS,IAIbG,SAAU,CACRX,UADQ,WAEN,OAAOY,KAAKC,aAAaD,KAAKH,WAGhCX,UALQ,WAMN,OAAOc,KAAKC,aAAaD,KAAKN,WAGhCL,aATQ,WAUN,OAAOW,KAAKC,aAAaD,KAAKF,eAIlCI,KAAM,WACJ,MAAO,CACLf,IAAK,IAAIgB,OAIbC,QAAS,CACPC,YADO,WAELL,KAAKb,IAAM,IAAIgB,OAInBG,QAAS,WACPN,KAAKK,cACLE,YAAYP,KAAKK,YAAa,O,UCvDlC,MAAMG,GAA2B,OAAgB,EAAQ,CAAC,CAAC,SAASC,GAAQ,CAAC,YAAY,qBAEzF","sources":["webpack://platypush/./src/components/widgets/DateTime/Index.vue","webpack://platypush/./src/components/widgets/DateTime/Index.vue?dfd6"],"sourcesContent":["<template>\n <div class=\"date-time\">\n <div class=\"date\" v-text=\"formatDate(now)\" v-if=\"_showDate\" />\n <div class=\"time\" v-text=\"formatTime(now, _showSeconds)\" v-if=\"_showTime\" />\n </div>\n</template>\n\n<script>\nimport Utils from \"@/Utils\";\n\n// Widget to show date and time\nexport default {\n name: 'DateTime',\n mixins: [Utils],\n props: {\n // If false then don't display the date.\n showDate: {\n required: false,\n default: true,\n },\n\n // If false then don't display the time.\n showTime: {\n required: false,\n default: true,\n },\n\n // If false then don't display the seconds.\n showSeconds: {\n required: false,\n default: true,\n },\n },\n\n computed: {\n _showTime() {\n return this.parseBoolean(this.showTime)\n },\n\n _showDate() {\n return this.parseBoolean(this.showDate)\n },\n\n _showSeconds() {\n return this.parseBoolean(this.showSeconds)\n },\n },\n\n data: function() {\n return {\n now: new Date(),\n };\n },\n\n methods: {\n refreshTime() {\n this.now = new Date()\n },\n },\n\n mounted: function() {\n this.refreshTime()\n setInterval(this.refreshTime, 1000)\n },\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.date-time {\n .date {\n font-size: 1.3em;\n }\n\n .time {\n font-size: 2em;\n }\n}\n</style>\n","import { render } from \"./Index.vue?vue&type=template&id=ca42eb9c&scoped=true\"\nimport script from \"./Index.vue?vue&type=script&lang=js\"\nexport * from \"./Index.vue?vue&type=script&lang=js\"\n\nimport \"./Index.vue?vue&type=style&index=0&id=ca42eb9c&lang=scss&scoped=true\"\n\nimport exportComponent from \"/home/blacklight/git_tree/platypush/platypush/backend/http/webapp/node_modules/vue-loader/dist/exportHelper.js\"\nconst __exports__ = /*#__PURE__*/exportComponent(script, [['render',render],['__scopeId',\"data-v-ca42eb9c\"]])\n\nexport default __exports__"],"names":["class","_showDate","now","_showTime","_showSeconds","name","mixins","Utils","props","showDate","required","default","showTime","showSeconds","computed","this","parseBoolean","data","Date","methods","refreshTime","mounted","setInterval","__exports__","render"],"sourceRoot":""}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue