Skip to content

Commit

Permalink
Merge pull request #49 from f3l/add_pagination
Browse files Browse the repository at this point in the history
Add pagination for cites view.
  • Loading branch information
pheerai authored Jan 5, 2019
2 parents a40a70e + 577f87d commit 9f99e47
Show file tree
Hide file tree
Showing 12 changed files with 288 additions and 28 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@ to
* Add Quotes
* Get a random quote
* List existing quotes


## Compilation ##

For a "release"-type binary with freshly generated CSS file, simply run

```
dub run --compiler=ldc2 -a=x86_64 -b=debug -c=generateCss
```

## Security Considerations ##

This tool is especially thought to run _on the same host as f3lbot_, and shall
Expand Down
2 changes: 1 addition & 1 deletion resources/static/cites.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions resources/templates/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,13 @@ html {
.clear {
clear: both;
}

.pagination_footer {
display: flex;
align-items: center;
justify-content: center;

.pagination {
margin: 4px 5px;
}
}
2 changes: 1 addition & 1 deletion resources/views/all.dt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ block content
p#desc Alle #{llen} bekannten Zitate.
div#citebody
- foreach(FullCiteData cite; cites)
include rendercite
include rendercite
10 changes: 10 additions & 0 deletions resources/views/all_paginated.dt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
extends ./layout

block content
- import citesystem.rest : FullCiteData;
p#desc.
F3L-Zitate Seite #{paginationInfo.currentPage}/#{paginationInfo.lastPage} – #[a(href="/all") Alle anzeigen]
div#citebody
- foreach(FullCiteData cite; cites)
include rendercite
include pagination_footer
2 changes: 1 addition & 1 deletion resources/views/index.dt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ extends ./layout

block content
p#desc Willkommen auf der internen Zitat-Datenbank des F3L-Teams!
p Hier können Zitat hinzugefügt sowie die bereits eingepflegten betrachtet werden.
p Hier können Zitat hinzugefügt sowie bereits eingepflegte betrachtet werden.
16 changes: 16 additions & 0 deletions resources/views/pagination_footer.dt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
div.pagination_footer
- if (paginationInfo.needsPreviousPage)
a.pagination.pagination_first(href="/all_paginated?page=1&pagesize=#{paginationInfo.pagesize}") «
a.pagination.pagination_previous(href="/all_paginated?page=#{paginationInfo.currentPage - 1}&pagesize=#{paginationInfo.pagesize}") ‹
- if (paginationInfo.needsFrontTruncation)
a.pagination.pagination_truncation …
- foreach(ulong mark; paginationInfo.pagesToShow)
- if (mark == paginationInfo.currentPage)
a.pagination_mark.pagination.pagination_current #{mark}
- else
a.pagination.pagination_mark(href="/all_paginated?page=#{mark}&pagesize=#{paginationInfo.pagesize}") #{mark}
- if (paginationInfo.needsBackTruncation)
a.pagination.pagination_truncation …
- if (paginationInfo.needsNextPage)
a.pagination.pagination_next(href="/all_paginated?page=#{paginationInfo.currentPage + 1}&pagesize=#{paginationInfo.pagesize}") ›
a.pagination.pagination_last(href="/all_paginated?pagesize=#{paginationInfo.pagesize}&page=#{paginationInfo.lastPage}") »
6 changes: 6 additions & 0 deletions source/citesystem/server/db.d
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module citesystem.server.db;

private import citesystem.server.paginationinfo : PaginationInfo;

/**
* Defines a commoninterface for Database adaptors.
*/
Expand All @@ -13,6 +15,10 @@ interface DB {
FullCiteData opIndex(long);
/// Retrieve all cites.
FullCiteData[] getAll();
/// Retrieve paginated. Takes page number and -size.
FullCiteData[] getPaginated(const PaginationInfo);
/// Get number of cites.
long count();
/// Add a citeation.
long addCite(string, string) @safe;
/// Modify a citation.
Expand Down
89 changes: 89 additions & 0 deletions source/citesystem/server/paginationinfo.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
module citesystem.server.paginationinfo;

private import diet.dom : Node;

public struct PaginationInfo {
const size_t pagesize;
const size_t currentPage;
const size_t numberOfElements;

this(size_t page, size_t pagesize,size_t count) {
this.currentPage = page;
this.pagesize = pagesize;
this.numberOfElements = count;
}

@property
size_t lastPage() const {
auto numberOfFullPages = numberOfElements / pagesize;
if (numberOfFullPages % pagesize == 0) {
return numberOfFullPages + 1;
} else {
return numberOfFullPages;
}
}

@property
size_t[] pagesToShow() const {
import std.range : iota;
import std.array : array;

auto firstPageLabel = firstPageLabel();
// assert(firstPageLabel > 0);
auto lastPageLabel = lastPageLabel();
// assert(lastPageLabel <= lastPage);
return iota(firstPageLabel, lastPageLabel + 1).array();
}

private ulong firstPageLabel() const {
return (currentPage > 3) ? currentPage - 3 : 1;
}

private ulong lastPageLabel() const {
import std.algorithm.comparison : min;
return min(currentPage + 3, lastPage);
}

@property
size_t firstCiteOffset() const {
return (pagesize * (currentPage - 1));
}

@property
size_t lastCite() const {
import std.algorithm.comparison : min;
return min(
pagesize * currentPage,
numberOfElements
);
}

@property
Node[] allMarks() const {
import diet.parser : parseDietRaw, identity;
import diet.input : InputFile;
InputFile inputFile = InputFile("pageinationInfo-footer", q{a(href="https://pheerai.de/") HP});

return parseDietRaw!identity(inputFile);
}

@property
bool needsFrontTruncation() const {
return firstPageLabel != 1;
}

@property
bool needsBackTruncation() const {
return lastPageLabel != lastPage;
}

@property
bool needsNextPage() const {
return currentPage != lastPage;
}

@property
bool needsPreviousPage() const {
return currentPage != 1;
}
}
79 changes: 56 additions & 23 deletions source/citesystem/server/sqlite.d
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,31 @@ private enum string[] PREPARE_DB = [
* Sqlite implementation of the DB interface.
*/
final class CiteSqlite : DB {
private import citesystem.rest : FullCiteData;
private import d2sqlite3 : Database, Row, Statement, SQLITE_OPEN_READWRITE, SQLITE_OPEN_CREATE;
private import std.array : empty;
private import std.datetime : Date;

private string dbname;
private Database db;
private Statement randomCite;
private Statement getCite;
private Statement addCiteQ;
private Statement modCite1;
private Statement modCite2;
private:
import citesystem.rest : FullCiteData;
import citesystem.server.paginationinfo : PaginationInfo;
import d2sqlite3 : Database, Row, Statement, SQLITE_OPEN_READWRITE, SQLITE_OPEN_CREATE;
import std.array : empty;
import std.datetime : Date;

string dbname;
Database db;
Statement randomCite;
Statement getCite;
Statement getAllCites;
Statement getPaginatedQ;
Statement addCiteQ;
Statement modCite1;
Statement modCite2;
Statement countCites;

public:
/**
* Creates a new Sqlite connection, including setup of the database if none exists.
* Params:
* dbname = Nameof the database. This defaults to a non-persistent in-memory database.
*/
public this(string dbname = ":memory:") {
this(string dbname = ":memory:") {
this.dbname = dbname;
this.db = Database(this.dbname, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
// scope(exit) this.db.close();
Expand All @@ -46,24 +52,35 @@ final class CiteSqlite : DB {
this.randomCite = db.prepare(
"SELECT * FROM showcites ORDER BY added DESC LIMIT :offset, 1");
this.getCite = db.prepare("SELECT * FROM showcites WHERE id==:id");
this.getAllCites = db.prepare("SELECT * FROM showcites ORDER BY id DESC");
this.getPaginatedQ = db.prepare("SELECT * FROM showcites ORDER BY id DESC " ~
"LIMIT :pagesize OFFSET :startcount");
this.addCiteQ = db.prepare("INSERT INTO cites (cite, addedby) VALUES (:cite,:addedby)");
this.modCite1 = db.prepare(
"INSERT INTO changes (citeid, changedby) VALUES (:citeid, :changedby)");
this.modCite2 = db.prepare("UPDATE OR IGNORE cites SET cite = :cite WHERE id == :id");
this.countCites = db.prepare("SELECT count(*) FROM cites");
}

public ~this() {
~this() {
db.close();
}

override long count() @trusted {
auto resultRange = countCites.execute;
scope(exit) countCites.reset;

return resultRange.oneValue!long;
}

/**
* Retrieves and returns a random citation from the Database.
* Returns:
* The retrieved citation.
*/
public FullCiteData getRandomCite() @trusted {
override FullCiteData getRandomCite() @trusted {
import std.random : uniform;
auto records = this.db.execute("SELECT COUNT(*) FROM cites").oneValue!long;
auto records = this.count;
const offset = uniform(0, records);
randomCite.bind(":offset", offset);
auto resCite = randomCite.execute();
Expand All @@ -81,7 +98,7 @@ final class CiteSqlite : DB {
* Returns:
* The retrieved citation.
*/
public FullCiteData get(long id) {
override FullCiteData get(long id) {
return this[id];
}

Expand All @@ -90,15 +107,29 @@ final class CiteSqlite : DB {
* Returns:
* An array containing all cites stored in the database.
*/
public FullCiteData[] getAll() {
override FullCiteData[] getAll() {
import std.algorithm : map;
import std.array : array;

auto replyAll = this.db.execute("SELECT * FROM showcites ORDER BY id DESC");
auto replyAll = getAllCites.execute;
FullCiteData[] cites = map!(a => toFullCiteData(a))(replyAll).array();
return cites;
}

override FullCiteData[] getPaginated(const PaginationInfo paginationInfo)
do {
import std.algorithm : map;
import std.array : array;

getPaginatedQ.bind(":pagesize", paginationInfo.pagesize);
getPaginatedQ.bind(":startcount", paginationInfo.firstCiteOffset);
scope(exit) getPaginatedQ.reset;

auto replyPage = getPaginatedQ.execute;
FullCiteData[] cites = map!(a => toFullCiteData(a))(replyPage).array();
return cites;
}

/**
* Add a citation.
* Params:
Expand All @@ -107,7 +138,7 @@ final class CiteSqlite : DB {
* Returns:
* The id of the added citation.
*/
public long addCite(string cite, string name) @trusted {
override long addCite(string cite, string name) @trusted {
addCiteQ.bind(":cite", cite);
addCiteQ.bind(":addedby", name);
addCiteQ.execute();
Expand All @@ -125,7 +156,7 @@ final class CiteSqlite : DB {
* Returns:
* The id of the modified citation.
*/
public long modifyCite(long id, string cite, string name) {
override long modifyCite(long id, string cite, string name) {
modCite1.bind(":citeid", id);
modCite1.bind(":changedby", name);
modCite2.bind(":cite", cite);
Expand All @@ -150,7 +181,7 @@ final class CiteSqlite : DB {
* FullCiteData of the cite with passed id, if it exists.
* FullCiteData with id "0" otherwise
*/
public FullCiteData opIndex(long id) @trusted
override FullCiteData opIndex(long id) @trusted
in {
assert(id > 0);
}
Expand All @@ -168,6 +199,8 @@ final class CiteSqlite : DB {
return cite;
}

private:

/**********
* toFullCiteData
*
Expand All @@ -177,7 +210,7 @@ final class CiteSqlite : DB {
* Returns: FullCiteData of the passed object
* Note: Will be replaced by cast-operator soon.
*/
private FullCiteData toFullCiteData(Row data) {
FullCiteData toFullCiteData(Row data) {
const id = data.peek!int("id");
string cite = data.peek!string("cite");
string isostring = data.peek!string("added");
Expand Down
17 changes: 16 additions & 1 deletion source/citesystem/server/system.d
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module citesystem.server.system;
final class CiteSystem {
private import citesystem.rest : FullCiteData;
private import citesystem.server.db : DB;
private import citesystem.server.paginationinfo : PaginationInfo;
private import std.conv : to;
private import std.random : uniform;
private import std.string : format;
Expand Down Expand Up @@ -69,7 +70,21 @@ final class CiteSystem {
render!("all.dt", title, cites, llen, start);
}

public void getAdd() const {
/**
* Get pageinated results (mock only)
*/
public void getAllPaginated(size_t page, size_t pagesize) {
string title = "Erste Zitate";
const count = this.db.count();
const count2 = this.db.count();
const paginationInfo = PaginationInfo(page, pagesize, count);
FullCiteData[] cites = this.db.getPaginated(paginationInfo);
render!("all_paginated.dt", title, cites, paginationInfo);
}

public void getAdd()
// const
{
string title = "Zitat hinzufügen";
render!("add.dt", title);
}
Expand Down
Loading

0 comments on commit 9f99e47

Please sign in to comment.