diff --git a/apiserver/database.py b/apiserver/database.py index be791ea..e8b6a8a 100644 --- a/apiserver/database.py +++ b/apiserver/database.py @@ -85,14 +85,16 @@ def get_reflist(): q = session.query(Reflist).order_by(Reflist.rid.desc()) return [dict(ref=x.ref, sid=x.sid, source=x.source, urlref=x.urlref) for x in q.all()] -def get_stories(maxage=60*60*24*2): +def get_stories(maxage=0, skip=0, limit=20): time = datetime.now().timestamp() - maxage session = Session() q = session.query(Reflist, Story.meta).\ join(Story).\ filter(Story.title != None).\ - filter(Story.meta['date'].as_integer() > time).\ - order_by(Story.meta['date'].desc()) + filter(maxage == 0 or Story.meta['date'].as_integer() > time).\ + order_by(Story.meta['date'].desc()).\ + offset(skip).\ + limit(limit) return [x[1] for x in q] def put_ref(ref, sid, source, urlref): diff --git a/apiserver/server.py b/apiserver/server.py index b3aedc4..29e2c45 100644 --- a/apiserver/server.py +++ b/apiserver/server.py @@ -41,7 +41,9 @@ cors = CORS(flask_app) @flask_app.route('/api') def api(): - stories = database.get_stories(settings.MAX_STORY_AGE) + skip = request.args.get('skip', 0) + limit = request.args.get('limit', 20) + stories = database.get_stories(skip=skip, limit=limit) res = Response(json.dumps({"stories": stories})) res.headers['content-type'] = 'application/json' return res diff --git a/webapp/src/components/Nav.svelte b/webapp/src/components/Nav.svelte index 5129646..6a6dcc0 100644 --- a/webapp/src/components/Nav.svelte +++ b/webapp/src/components/Nav.svelte @@ -1,5 +1,22 @@ diff --git a/webapp/src/routes/[id].json.js b/webapp/src/routes/[id].json.js index c9f5c7f..daa8d5f 100644 --- a/webapp/src/routes/[id].json.js +++ b/webapp/src/routes/[id].json.js @@ -1,6 +1,7 @@ import fetch from 'isomorphic-fetch'; -const API_URL = process.env.API_URL || 'http://news.1j.nz'; +// const API_URL = process.env.API_URL || 'http://news.1j.nz'; +const API_URL = process.env.API_URL || 'http://localhost:33842'; export async function get(req, res) { const response = await fetch(`${API_URL}/api/${req.params.id}`); diff --git a/webapp/src/routes/[id].svelte b/webapp/src/routes/[id].svelte index 6b34eaf..b6df878 100644 --- a/webapp/src/routes/[id].svelte +++ b/webapp/src/routes/[id].svelte @@ -23,6 +23,22 @@ @@ -29,10 +56,6 @@
{#each stories as story} -
{/each}
+ + diff --git a/webapp/src/routes/search.json.js b/webapp/src/routes/search.json.js new file mode 100644 index 0000000..b2c83ec --- /dev/null +++ b/webapp/src/routes/search.json.js @@ -0,0 +1,13 @@ +import fetch from 'isomorphic-fetch'; + +const API_URL = process.env.API_URL || 'http://news.1j.nz'; + +export async function get(req, res) { + const { skip, limit } = { + skip: req.query.skip || 0, + limit: req.query.limit || 20, + }; + const response = await fetch(`${API_URL}/api/search?q=${req.query.q}&skip=${skip}&limit=${limit}`); + res.writeHead(response.status, { 'Content-Type': 'application/json' }); + res.end(await response.text()); +} \ No newline at end of file diff --git a/webapp/src/routes/search.svelte b/webapp/src/routes/search.svelte new file mode 100644 index 0000000..cbe6294 --- /dev/null +++ b/webapp/src/routes/search.svelte @@ -0,0 +1,103 @@ + + + + + + + + QotNews + + + + +
+ {#each stories as story} + + {/each} +
+ + diff --git a/webclient/src/App.js b/webclient/src/App.js index c4c2063..4c74151 100644 --- a/webclient/src/App.js +++ b/webclient/src/App.js @@ -66,12 +66,12 @@ class App extends React.Component { - } /> + } />
} /> - } /> + } /> diff --git a/webclient/src/Style-light.css b/webclient/src/Style-light.css index 3722ca8..323ff31 100644 --- a/webclient/src/Style-light.css +++ b/webclient/src/Style-light.css @@ -229,3 +229,13 @@ span.source { .indented { padding: 0 0 0 1rem; } + +.pagination { + margin: 3rem 0; + display: flex; + flex-direction: row; + justify-content: space-between; +} +.pagination-link.is-right { + margin-left: auto; +} diff --git a/webclient/src/pages/Feed.js b/webclient/src/pages/Feed.js index 213b00f..fc899e5 100644 --- a/webclient/src/pages/Feed.js +++ b/webclient/src/pages/Feed.js @@ -1,20 +1,25 @@ import React from 'react'; import { Helmet } from 'react-helmet'; import localForage from 'localforage'; +import { Link } from "react-router-dom"; import { StoryItem } from '../components/StoryItem.js'; class Feed extends React.Component { constructor(props) { super(props); + const query = new URLSearchParams(this.props.location.search); + this.state = { stories: JSON.parse(localStorage.getItem('stories')) || false, error: false, + skip: +query.get('skip') || 0, + limit: +query.get('limit') || 20 }; } componentDidMount() { - fetch('/api') + fetch(`/api?skip=${this.state.skip}&limit=${this.state.limit}`) .then(res => res.json()) .then( (result) => { @@ -51,6 +56,8 @@ class Feed extends React.Component { render() { const stories = this.state.stories; const error = this.state.error; + const skip = this.state.skip; + const limit = this.state.limit; return (
@@ -59,9 +66,21 @@ class Feed extends React.Component { {error &&

Connection error?

} {stories ? stories.map(story => ) :

loading...

} + +
+ {Number(skip) > 0 && Previous} + {stories.length == Number(limit) && Next} +
); } } +Feed.key = function (props) { + const query = new URLSearchParams(props.location.search); + const skip = query.get('skip') || 0; + const limit = query.get('limit') || 20; + return `skip=${skip}&limit=${limit}`; +} + export default Feed;