aboutsummaryrefslogtreecommitdiff
path: root/pyaggr3g470r/controllers
diff options
context:
space:
mode:
authorCédric Bonhomme <cedric@cedricbonhomme.org>2015-11-25 22:45:43 +0100
committerCédric Bonhomme <cedric@cedricbonhomme.org>2015-11-25 22:45:43 +0100
commitb2618e9404b84cc62d4becb02436233a0d53b375 (patch)
treea31f2dc76d23967fa0243374cf475923a4b7e451 /pyaggr3g470r/controllers
parentUpdated default platform URL (for Heroku...). (diff)
downloadnewspipe-b2618e9404b84cc62d4becb02436233a0d53b375.tar.gz
newspipe-b2618e9404b84cc62d4becb02436233a0d53b375.tar.bz2
newspipe-b2618e9404b84cc62d4becb02436233a0d53b375.zip
Rfactorization. Just a start...
Diffstat (limited to 'pyaggr3g470r/controllers')
-rw-r--r--pyaggr3g470r/controllers/__init__.py8
-rw-r--r--pyaggr3g470r/controllers/abstract.py116
-rw-r--r--pyaggr3g470r/controllers/article.py73
-rw-r--r--pyaggr3g470r/controllers/feed.py70
-rw-r--r--pyaggr3g470r/controllers/icon.py23
-rw-r--r--pyaggr3g470r/controllers/user.py7
6 files changed, 0 insertions, 297 deletions
diff --git a/pyaggr3g470r/controllers/__init__.py b/pyaggr3g470r/controllers/__init__.py
deleted file mode 100644
index ad77fa1d..00000000
--- a/pyaggr3g470r/controllers/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from .feed import FeedController
-from .article import ArticleController
-from .user import UserController
-from .icon import IconController
-
-
-__all__ = ['FeedController', 'ArticleController', 'UserController',
- 'IconController']
diff --git a/pyaggr3g470r/controllers/abstract.py b/pyaggr3g470r/controllers/abstract.py
deleted file mode 100644
index f33d241e..00000000
--- a/pyaggr3g470r/controllers/abstract.py
+++ /dev/null
@@ -1,116 +0,0 @@
-import logging
-from flask import g
-from bootstrap import db
-from sqlalchemy import or_
-from werkzeug.exceptions import Forbidden, NotFound
-
-logger = logging.getLogger(__name__)
-
-
-class AbstractController(object):
- _db_cls = None # reference to the database class
- _user_id_key = 'user_id'
-
- def __init__(self, user_id=None):
- """User id is a right management mechanism that should be used to
- filter objects in database on their denormalized "user_id" field
- (or "id" field for users).
- Should no user_id be provided, the Controller won't apply any filter
- allowing for a kind of "super user" mode.
- """
- self.user_id = user_id
- try:
- if self.user_id is not None \
- and self.user_id != g.user.id and not g.user.is_admin():
- self.user_id = g.user.id
- except RuntimeError: # passing on out of context errors
- pass
-
- def _to_filters(self, **filters):
- """
- Will translate filters to sqlalchemy filter.
- This method will also apply user_id restriction if available.
-
- each parameters of the function is treated as an equality unless the
- name of the parameter ends with either "__gt", "__lt", "__ge", "__le",
- "__ne", "__in" ir "__like".
- """
- db_filters = set()
- for key, value in filters.items():
- if key == '__or__':
- db_filters.add(or_(*self._to_filters(**value)))
- elif key.endswith('__gt'):
- db_filters.add(getattr(self._db_cls, key[:-4]) > value)
- elif key.endswith('__lt'):
- db_filters.add(getattr(self._db_cls, key[:-4]) < value)
- elif key.endswith('__ge'):
- db_filters.add(getattr(self._db_cls, key[:-4]) >= value)
- elif key.endswith('__le'):
- db_filters.add(getattr(self._db_cls, key[:-4]) <= value)
- elif key.endswith('__ne'):
- db_filters.add(getattr(self._db_cls, key[:-4]) != value)
- elif key.endswith('__in'):
- db_filters.add(getattr(self._db_cls, key[:-4]).in_(value))
- elif key.endswith('__like'):
- db_filters.add(getattr(self._db_cls, key[:-6]).like(value))
- elif key.endswith('__ilike'):
- db_filters.add(getattr(self._db_cls, key[:-7]).ilike(value))
- else:
- db_filters.add(getattr(self._db_cls, key) == value)
- return db_filters
-
- def _get(self, **filters):
- """ Will add the current user id if that one is not none (in which case
- the decision has been made in the code that the query shouldn't be user
- dependant) and the user is not an admin and the filters doesn't already
- contains a filter for that user.
- """
- if self._user_id_key is not None and self.user_id \
- and filters.get(self._user_id_key) != self.user_id:
- filters[self._user_id_key] = self.user_id
- return self._db_cls.query.filter(*self._to_filters(**filters))
-
- def get(self, **filters):
- """Will return one single objects corresponding to filters"""
- obj = self._get(**filters).first()
-
- if obj and not self._has_right_on(obj):
- raise Forbidden({'message': 'No authorized to access %r (%r)'
- % (self._db_cls.__class__.__name__, filters)})
- if not obj:
- raise NotFound({'message': 'No %r (%r)'
- % (self._db_cls.__class__.__name__, filters)})
- return obj
-
- def create(self, **attrs):
- assert self._user_id_key is None or self._user_id_key in attrs \
- or self.user_id is not None, \
- "You must provide user_id one way or another"
-
- if self._user_id_key is not None and self._user_id_key not in attrs:
- attrs[self._user_id_key] = self.user_id
- obj = self._db_cls(**attrs)
- db.session.add(obj)
- db.session.commit()
- return obj
-
- def read(self, **filters):
- return self._get(**filters)
-
- def update(self, filters, attrs):
- result = self._get(**filters).update(attrs, synchronize_session=False)
- db.session.commit()
- return result
-
- def delete(self, obj_id):
- obj = self.get(id=obj_id)
- db.session.delete(obj)
- db.session.commit()
- return obj
-
- def _has_right_on(self, obj):
- # user_id == None is like being admin
- if self._user_id_key is None:
- return True
- return self.user_id is None \
- or getattr(obj, self._user_id_key, None) == self.user_id
diff --git a/pyaggr3g470r/controllers/article.py b/pyaggr3g470r/controllers/article.py
deleted file mode 100644
index 21b4b5e7..00000000
--- a/pyaggr3g470r/controllers/article.py
+++ /dev/null
@@ -1,73 +0,0 @@
-import re
-import logging
-from sqlalchemy import func
-
-from bootstrap import db
-from .abstract import AbstractController
-from pyaggr3g470r.controllers import FeedController
-from pyaggr3g470r.models import Article
-
-logger = logging.getLogger(__name__)
-
-
-class ArticleController(AbstractController):
- _db_cls = Article
-
- def get(self, **filters):
- article = super(ArticleController, self).get(**filters)
- if not article.readed:
- self.update({'id': article.id}, {'readed': True})
- return article
-
- def challenge(self, ids):
- """Will return each id that wasn't found in the database."""
- for id_ in ids:
- if self.read(**id_).first():
- continue
- yield id_
-
- def count_by_feed(self, **filters):
- if self.user_id:
- filters['user_id'] = self.user_id
- return dict(db.session.query(Article.feed_id, func.count(Article.id))
- .filter(*self._to_filters(**filters))
- .group_by(Article.feed_id).all())
-
- def count_by_user_id(self, **filters):
- return dict(db.session.query(Article.user_id,
- func.count(Article.id))
- .filter(*self._to_filters(**filters))
- .group_by(Article.user_id).all())
-
- def create(self, **attrs):
- # handling special denorm for article rights
- assert 'feed_id' in attrs
- feed = FeedController(
- attrs.get('user_id', self.user_id)).get(id=attrs['feed_id'])
- if 'user_id' in attrs:
- assert feed.user_id == attrs['user_id'] or self.user_id is None
- attrs['user_id'] = feed.user_id
-
- # handling feed's filters
- for filter_ in feed.filters or []:
- match = False
- if filter_.get('type') == 'regex':
- match = re.match(filter_['pattern'], attrs.get('title', ''))
- elif filter_.get('type') == 'simple match':
- match = filter_['pattern'] in attrs.get('title', '')
- take_action = match and filter_.get('action on') == 'match' \
- or not match and filter_.get('action on') == 'no match'
-
- if not take_action:
- continue
-
- if filter_.get('action') == 'mark as read':
- attrs['readed'] = True
- logger.warn("article %s will be created as read",
- attrs['link'])
- elif filter_.get('action') == 'mark as favorite':
- attrs['like'] = True
- logger.warn("article %s will be created as liked",
- attrs['link'])
-
- return super().create(**attrs)
diff --git a/pyaggr3g470r/controllers/feed.py b/pyaggr3g470r/controllers/feed.py
deleted file mode 100644
index 90ee6ea5..00000000
--- a/pyaggr3g470r/controllers/feed.py
+++ /dev/null
@@ -1,70 +0,0 @@
-#! /usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# pyAggr3g470r - A Web based news aggregator.
-# Copyright (C) 2010-2015 Cédric Bonhomme - https://www.cedricbonhomme.org
-#
-# For more information : https://bitbucket.org/cedricbonhomme/pyaggr3g470r/
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import logging
-from datetime import datetime, timedelta
-
-import conf
-from .abstract import AbstractController
-from .icon import IconController
-from pyaggr3g470r.models import Feed
-
-logger = logging.getLogger(__name__)
-DEFAULT_LIMIT = 5
-DEFAULT_REFRESH_RATE = 60
-DEFAULT_MAX_ERROR = conf.DEFAULT_MAX_ERROR
-
-
-class FeedController(AbstractController):
- _db_cls = Feed
-
- def list_late(self, max_last, max_error=DEFAULT_MAX_ERROR,
- limit=DEFAULT_LIMIT):
- return [feed for feed in self.read(
- error_count__lt=max_error, enabled=True,
- last_retrieved__lt=max_last)
- .order_by('last_retrieved')
- .limit(limit)]
-
- def list_fetchable(self, max_error=DEFAULT_MAX_ERROR, limit=DEFAULT_LIMIT,
- refresh_rate=DEFAULT_REFRESH_RATE):
- now = datetime.now()
- max_last = now - timedelta(minutes=refresh_rate)
- feeds = self.list_late(max_last, max_error, limit)
- if feeds:
- self.update({'id__in': [feed.id for feed in feeds]},
- {'last_retrieved': now})
- return feeds
-
- def _ensure_icon(self, attrs):
- if not attrs.get('icon_url'):
- return
- icon_contr = IconController()
- if not icon_contr.read(url=attrs['icon_url']).count():
- icon_contr.create(**{'url': attrs['icon_url']})
-
- def create(self, **attrs):
- self._ensure_icon(attrs)
- return super().create(**attrs)
-
- def update(self, filters, attrs):
- self._ensure_icon(attrs)
- return super().update(filters, attrs)
diff --git a/pyaggr3g470r/controllers/icon.py b/pyaggr3g470r/controllers/icon.py
deleted file mode 100644
index 194c601c..00000000
--- a/pyaggr3g470r/controllers/icon.py
+++ /dev/null
@@ -1,23 +0,0 @@
-import base64
-import requests
-from pyaggr3g470r.models import Icon
-from .abstract import AbstractController
-
-
-class IconController(AbstractController):
- _db_cls = Icon
- _user_id_key = None
-
- def _build_from_url(self, attrs):
- if 'url' in attrs and 'content' not in attrs:
- resp = requests.get(attrs['url'], verify=False)
- attrs.update({'url': resp.url,
- 'mimetype': resp.headers.get('content-type', None),
- 'content': base64.b64encode(resp.content).decode('utf8')})
- return attrs
-
- def create(self, **attrs):
- return super().create(**self._build_from_url(attrs))
-
- def update(self, filters, attrs):
- return super().update(filters, self._build_from_url(attrs))
diff --git a/pyaggr3g470r/controllers/user.py b/pyaggr3g470r/controllers/user.py
deleted file mode 100644
index c6c1d545..00000000
--- a/pyaggr3g470r/controllers/user.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from .abstract import AbstractController
-from pyaggr3g470r.models import User
-
-
-class UserController(AbstractController):
- _db_cls = User
- _user_id_key = 'id'
bgstack15