diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/web/js/actions/MenuActions.js | 2 | ||||
-rw-r--r-- | src/web/js/components/MainApp.react.js | 26 | ||||
-rw-r--r-- | src/web/js/components/Menu.react.js | 10 | ||||
-rw-r--r-- | src/web/js/components/MiddlePanel.react.js | 8 | ||||
-rw-r--r-- | src/web/js/components/Navbar.react.js | 91 | ||||
-rw-r--r-- | src/web/js/components/RightPanel.react.js | 13 | ||||
-rw-r--r-- | src/web/js/stores/MenuStore.js | 3 | ||||
-rw-r--r-- | src/web/static/css/customized-bootstrap.css | 11 | ||||
-rw-r--r-- | src/web/templates/home2.html | 82 | ||||
-rw-r--r-- | src/web/views/feed.py | 5 | ||||
-rw-r--r-- | src/web/views/views.py | 2 |
11 files changed, 145 insertions, 108 deletions
diff --git a/src/web/js/actions/MenuActions.js b/src/web/js/actions/MenuActions.js index 4b17d084..fa30474e 100644 --- a/src/web/js/actions/MenuActions.js +++ b/src/web/js/actions/MenuActions.js @@ -11,6 +11,8 @@ var MenuActions = { type: ActionTypes.RELOAD_MENU, feeds: payload.feeds, categories: payload.categories, + is_admin: payload.is_admin, + crawling_method: payload.crawling_method, all_unread_count: payload.all_unread_count, }); }); diff --git a/src/web/js/components/MainApp.react.js b/src/web/js/components/MainApp.react.js index b448f808..cbdc5833 100644 --- a/src/web/js/components/MainApp.react.js +++ b/src/web/js/components/MainApp.react.js @@ -1,7 +1,8 @@ var React = require('react'); -var Col = require('react-bootstrap/Col'); -var Grid = require('react-bootstrap/Grid'); +var Col = require('react-bootstrap/lib/Col'); +var Grid = require('react-bootstrap/lib/Grid'); +var JarrNavBar = require('./Navbar.react'); var Menu = require('./Menu.react'); var MiddlePanel = require('./MiddlePanel.react'); var RightPanel = require('./RightPanel.react'); @@ -9,15 +10,18 @@ var RightPanel = require('./RightPanel.react'); var MainApp = React.createClass({ render: function() { - return (<Grid fluid id="jarr-container"> - <Menu /> - <Col id="middle-panel" mdOffset={3} lgOffset={2} - xs={2} sm={2} md={4} lg={4}> - <MiddlePanel.MiddlePanelFilter /> - <MiddlePanel.MiddlePanel /> - </Col> - <RightPanel /> - </Grid> + return (<div> + <JarrNavBar /> + <Grid fluid id="jarr-container"> + <Menu /> + <Col id="middle-panel" mdOffset={3} lgOffset={2} + xs={4} sm={4} md={4} lg={4}> + <MiddlePanel.MiddlePanelFilter /> + <MiddlePanel.MiddlePanel /> + </Col> + <RightPanel /> + </Grid> + </div> ); }, }); diff --git a/src/web/js/components/Menu.react.js b/src/web/js/components/Menu.react.js index 0d739e4e..ad28015c 100644 --- a/src/web/js/components/Menu.react.js +++ b/src/web/js/components/Menu.react.js @@ -1,9 +1,9 @@ var React = require('react'); -var Col = require('react-bootstrap/Col'); -var Badge = require('react-bootstrap/Badge'); -var Button = require('react-bootstrap/Button'); -var ButtonGroup = require('react-bootstrap/ButtonGroup'); -var Glyphicon = require('react-bootstrap/Glyphicon'); +var Col = require('react-bootstrap/lib/Col'); +var Badge = require('react-bootstrap/lib/Badge'); +var Button = require('react-bootstrap/lib/Button'); +var ButtonGroup = require('react-bootstrap/lib/ButtonGroup'); +var Glyphicon = require('react-bootstrap/lib/Glyphicon'); var MenuStore = require('../stores/MenuStore'); var MenuActions = require('../actions/MenuActions'); diff --git a/src/web/js/components/MiddlePanel.react.js b/src/web/js/components/MiddlePanel.react.js index 6bfdaaa9..fd291624 100644 --- a/src/web/js/components/MiddlePanel.react.js +++ b/src/web/js/components/MiddlePanel.react.js @@ -1,9 +1,9 @@ var React = require('react'); -var Row = require('react-bootstrap/Row'); -var Button = require('react-bootstrap/Button'); -var ButtonGroup = require('react-bootstrap/ButtonGroup'); -var Glyphicon = require('react-bootstrap/Glyphicon'); +var Row = require('react-bootstrap/lib/Row'); +var Button = require('react-bootstrap/lib/Button'); +var ButtonGroup = require('react-bootstrap/lib/ButtonGroup'); +var Glyphicon = require('react-bootstrap/lib/Glyphicon'); var MiddlePanelStore = require('../stores/MiddlePanelStore'); var MiddlePanelActions = require('../actions/MiddlePanelActions'); diff --git a/src/web/js/components/Navbar.react.js b/src/web/js/components/Navbar.react.js new file mode 100644 index 00000000..56de178e --- /dev/null +++ b/src/web/js/components/Navbar.react.js @@ -0,0 +1,91 @@ +var React = require('react'); +var Glyphicon = require('react-bootstrap/lib/Glyphicon'); +var Nav = require('react-bootstrap/lib/Nav'); +var NavItem = require('react-bootstrap/lib/NavItem'); +var Navbar = require('react-bootstrap/lib/Navbar'); +var NavDropdown = require('react-bootstrap/lib/NavDropdown'); +var MenuItem = require('react-bootstrap/lib/MenuItem'); +var Button = require('react-bootstrap/lib/Button'); +var Input = require('react-bootstrap/lib/Input'); + +var MenuStore = require('../stores/MenuStore'); + +JarrNavBar = React.createClass({ + getInitialState: function() { + return {is_admin: MenuStore._datas.is_admin, + crawling_method: MenuStore._datas.crawling_method}; + }, + buttonFetch: function() { + if(this.state.is_admin && this.state.crawling_method != 'http') { + return <NavItem eventKey={2} href="/fetch"><Glyphicon glyph="import" />Fetch</NavItem>; + } + }, + buttonAdmin: function() { + if(this.state.is_admin) { + return (<NavDropdown title={<Glyphicon glyph='cog' />} + id='admin-dropdown'> + <MenuItem href="/admin/dashboard"> + <Glyphicon glyph="dashboard" />Dashboard + </MenuItem> + </NavDropdown>); + } + }, + render: function() { + var gl_title = (<span> + <Glyphicon glyph="plus-sign" />Add a new feed + </span>); + return (<Navbar fixedTop inverse className="navbar-custom"> + <Navbar.Header> + <Navbar.Brand> + <a href="/">JARR</a> + </Navbar.Brand> + <Navbar.Toggle /> + </Navbar.Header> + <Nav pullRight> + <Navbar.Form pullLeft> + <form action="/feed/bookmarklet" method="GET"> + <Input name="url" type="text" + placeholder="Add a new feed" /> + <Button type="submit">Submit</Button> + </form> + </Navbar.Form> + {this.buttonFetch()} + <NavDropdown title="Feed" id="feed-mgmt-dropdown"> + <MenuItem href="/feeds/inactives">Inactive</MenuItem> + <MenuItem href="/articles/history">History</MenuItem> + <MenuItem href="/feeds/">All</MenuItem> + </NavDropdown> + {this.buttonAdmin()} + <NavDropdown title={<Glyphicon glyph='user' />} + id="user-dropdown"> + <MenuItem href="/user/profile"> + <Glyphicon glyph="user" />Profile + </MenuItem> + <MenuItem href="/user/management"> + <Glyphicon glyph="cog" />Your data + </MenuItem> + <MenuItem href="/about"> + <Glyphicon glyph="question-sign" />About + </MenuItem> + <MenuItem href="/logout"> + <Glyphicon glyph="log-out" />Logout + </MenuItem> + </NavDropdown> + </Nav> + </Navbar> + ); + }, + componentDidMount: function() { + MenuStore.addChangeListener(this._onChange); + }, + componentWillUnmount: function() { + MenuStore.removeChangeListener(this._onChange); + }, + _onChange: function() { + var datas = MenuStore.getAll(); + this.setState({is_admin: datas.is_admin, + crawling_method: datas.crawling_method}); + }, +}); + +module.exports = JarrNavBar; diff --git a/src/web/js/components/RightPanel.react.js b/src/web/js/components/RightPanel.react.js index fda7c976..e9485511 100644 --- a/src/web/js/components/RightPanel.react.js +++ b/src/web/js/components/RightPanel.react.js @@ -1,8 +1,8 @@ var React = require('react'); -var Col = require('react-bootstrap/Col'); -var Glyphicon = require('react-bootstrap/Glyphicon'); -var Button = require('react-bootstrap/Button'); -var ButtonGroup = require('react-bootstrap/ButtonGroup'); +var Col = require('react-bootstrap/lib/Col'); +var Glyphicon = require('react-bootstrap/lib/Glyphicon'); +var Button = require('react-bootstrap/lib/Button'); +var ButtonGroup = require('react-bootstrap/lib/ButtonGroup'); var RightPanelActions = require('../actions/RightPanelActions'); var RightPanelStore = require('../stores/RightPanelStore'); @@ -293,7 +293,6 @@ var RightPanel = React.createClass({ return <li>{this.state.article.title}</li>; }, render: function() { - var content = null; var brd_category = null; var brd_feed = null; var brd_article = null; @@ -329,9 +328,9 @@ var RightPanel = React.createClass({ key={this.state.category.id} />); } - return (<Col id="right-panel" xsOffset={2} smOffset={2} + return (<Col id="right-panel" xsOffset={4} smOffset={4} mdOffset={7} lgOffset={6} - xs={10} sm={10} md={5} lg={6}> + xs={8} sm={8} md={5} lg={6}> {breadcrum} {cntnt} </Col> diff --git a/src/web/js/stores/MenuStore.js b/src/web/js/stores/MenuStore.js index edc90a38..b8f50fd9 100644 --- a/src/web/js/stores/MenuStore.js +++ b/src/web/js/stores/MenuStore.js @@ -8,6 +8,7 @@ var assign = require('object-assign'); var MenuStore = assign({}, EventEmitter.prototype, { _datas: {filter: 'all', feeds: {}, categories: {}, active_type: null, active_id: null, + is_admin: false, crawling_method: 'classic', all_unread_count: 0}, getAll: function() { return this._datas; @@ -45,6 +46,8 @@ MenuStore.dispatchToken = JarrDispatcher.register(function(action) { case ActionTypes.RELOAD_MENU: MenuStore._datas['feeds'] = action.feeds; MenuStore._datas['categories'] = action.categories; + MenuStore._datas['is_admin'] = action.is_admin; + MenuStore._datas['crawling_method'] = action.crawling_method; MenuStore._datas['all_unread_count'] = action.all_unread_count; MenuStore.emitChange(); break; diff --git a/src/web/static/css/customized-bootstrap.css b/src/web/static/css/customized-bootstrap.css index 9f3febfc..db789f56 100644 --- a/src/web/static/css/customized-bootstrap.css +++ b/src/web/static/css/customized-bootstrap.css @@ -8,11 +8,20 @@ div.top { height: 0; } -.navbar-custom { +nav.navbar-custom { background-color: #205081; border: #205081; border-radius: 0; } +nav.navbar-custom>div.container { + width: 100%; +} +nav.navbar-custom span.glyphicon { + margin-right: 5px; +} +nav.navbar-custom button { + margin-left: 5px; +} .navbar-custom .navbar-nav > li > a { color: #FFFFFF; diff --git a/src/web/templates/home2.html b/src/web/templates/home2.html index 36dd8f19..4389ae6f 100644 --- a/src/web/templates/home2.html +++ b/src/web/templates/home2.html @@ -16,85 +16,7 @@ {% endblock %} </head> <body> - <nav class="navbar navbar-inverse navbar-fixed-top navbar-custom" role="navigation"> - <div class="container-fluid"> - <div class="navbar-header"> - <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse"> - <span class="sr-only">Toggle navigation</span> - <span class="icon-bar"></span> - <span class="icon-bar"></span> - <span class="icon-bar"></span> - </button> - <a class="navbar-brand" href="{{ url_for("home") }}">JARR</a> - {% if head_titles %} - <p class="navbar-text" style="max-height: 20px; overflow: hidden"> - {{ " - ".join(head_titles) }} - </p> - {% endif %} - </div> - - <!-- Collect the nav links, forms, and other content for toggling --> - <div class="collapse navbar-collapse navbar-ex1-collapse"> - <ul class="nav navbar-nav navbar-right"> - {% if g.user.is_authenticated %} - <!-- <li><a href="{{ url_for("feed.form") }}"><span class="glyphicon glyphicon-plus-sign"></span> {{ _('Add a feed') }}</a></li> --> - <li class="dropdown"> - <a href="#" class="dropdown-toggle" data-toggle="dropdown"> - <div><span class="glyphicon glyphicon-plus-sign"></span> {{ _('Add a feed') }}</div> - </a> - <ul class="dropdown-menu"> - <li> - <form action="{{ url_for('feed.bookmarklet') }}" class="navbar-form navbar-left" method="GET" name="save"> - <div class="input-group input-group-inline"> - <input class="form-control" name="url" type="url" placeholder="{{_("site or feed url")}}" required="required"/> - <span class="input-group-btn"> - <button type="submit" class="btn btn-default" /><span class="glyphicon glyphicon-plus"></span></button> - </span> - </div><!-- /input-group --> - </form> - </li> - </ul> - </li> - {% if conf.CRAWLING_METHOD == "classic" and (not conf.ON_HEROKU or g.user.is_admin()) %} - <li><a href="/fetch"><span class="glyphicon glyphicon-import"></span> {{ _('Fetch') }}</a></li> - {% endif %} - <li class="dropdown"> - <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{ _('Feed') }} <b class="caret"></b></a> - <ul class="dropdown-menu"> - <li><a href="{{ url_for("feeds.update", action="read") }}">{{ _('Mark all as read') }}</a></li> - <li><a href="{{ url_for("feeds.update", action="read", nb_days="1") }}">{{ _('Mark all as read older than yesterday') }}</a></li> - <li><a href="{{ url_for("feeds.update", action="read", nb_days="5") }}">{{ gettext('Mark all as read older than %(days)s days', days=5) }}</a></li> - <li><a href="{{ url_for("feeds.update", action="read", nb_days="10") }}">{{ gettext('Mark all as read older than %(days)s days', days=10) }}</a></li> - <li role="presentation" class="divider"></li> - <li><a href="{{ url_for("feeds.inactives") }}">{{ _('Inactive') }}</a></li> - <li><a href="{{ url_for("articles.history") }}">{{ _('History') }}</a></li> - <li><a href="{{ url_for("feeds.feeds") }}">{{ _('All') }}</a></li> - </ul> - </li> - <li class="dropdown"> - <a href="#" class="dropdown-toggle" data-toggle="dropdown"> - <div><span class="glyphicon glyphicon-user"></span> <b class="caret"></b></div> - </a> - <ul class="dropdown-menu"> - <li><a href="{{ url_for("user.profile") }}"><span class="glyphicon glyphicon-user"></span> {{ _('Profile') }}</a></li> - <li><a href="{{ url_for("user.management") }}"><span class="glyphicon glyphicon-cog"></span> {{ _('Your data') }}</a></li> - <li><a href="{{ url_for("about") }}"><span class="glyphicon glyphicon-question-sign"></span> {{ _('About') }}</a></li> - {% if g.user.is_admin() %} - <li role="presentation" class="divider"></li> - <li><a href="{{ url_for("admin.dashboard") }}"><span class="glyphicon glyphicon-dashboard"></span> {{ _('Dashboard') }}</a></li> - <li role="presentation" class="divider"></li> - {% endif %} - <li><a href="{{ url_for("logout") }}"><span class="glyphicon glyphicon-log-out"></span> {{ _('Logout') }}</a></li> - </ul> - </li> - {% else %} - <li><a href="{{ url_for("about") }}"><span class="glyphicon glyphicon-question-sign"></span> {{ _('About') }}</a></li> - {% endif %} - </ul> - </div><!-- /.navbar-collapse --> - </div><!-- /.container --> - </nav> - <section id="jarrapp"></section> - <script type="text/javascript" src="{{ url_for('static', filename = 'js/bundle.min.js') }}"></script> + <section id="jarrapp" /> </body> + <script type="text/javascript" src="{{ url_for('static', filename = 'js/bundle.min.js') }}"></script> </html> diff --git a/src/web/views/feed.py b/src/web/views/feed.py index 69972958..9de45a7e 100644 --- a/src/web/views/feed.py +++ b/src/web/views/feed.py @@ -1,5 +1,6 @@ #! /usr/bin/env python # -*- coding: utf-8 - +import logging import requests.exceptions from datetime import datetime, timedelta from sqlalchemy import desc @@ -18,6 +19,7 @@ from web.forms import AddFeedForm from web.controllers import (CategoryController, FeedController, ArticleController) +logger = logging.getLogger(__name__) feeds_bp = Blueprint('feeds', __name__, url_prefix='/feeds') feed_bp = Blueprint('feed', __name__, url_prefix='/feed') @@ -114,6 +116,9 @@ def bookmarklet(): flash(gettext("Impossible to connect to the address: {}.".format(url)), "danger") return redirect(url_for('home')) + except Exception: + logger.exception('something bad happened when fetching %r', url) + return redirect(url_for('home')) if not feed.get('link'): feed['enabled'] = False flash(gettext("Couldn't find a feed url, you'll need to find a Atom or" diff --git a/src/web/views/views.py b/src/web/views/views.py index f8549e93..1aed912d 100644 --- a/src/web/views/views.py +++ b/src/web/views/views.py @@ -262,6 +262,8 @@ def get_menu(): categories[feed['category_id']]['unread'] += feed['unread'] categories[feed['category_id']]['feeds'].append(feed_id) return jsonify(**{'feeds': feeds, 'categories': categories, + 'crawling_method': conf.CRAWLING_METHOD, + 'is_admin': g.user.is_admin(), 'all_unread_count': sum(unread.values())}) |