Skip to content

Commit 017dcc8

Browse files
committed
Refactoring und neue Daten
1 parent de59f64 commit 017dcc8

5 files changed

Lines changed: 153 additions & 253 deletions

File tree

lib/parteiduell_backend.dart

Lines changed: 45 additions & 252 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import 'dart:convert';
22
import 'dart:io';
3+
import 'package:alfred/alfred.dart';
34
import 'package:http/http.dart' as http;
45

5-
import 'package:parteiduell_backend/models/quiz_question.dart';
66
import 'package:parteiduell_backend/models/quizthese.dart';
7+
import 'package:parteiduell_backend/routes/all_parties.dart';
8+
import 'package:parteiduell_backend/routes/all_sources.dart';
9+
import 'package:parteiduell_backend/routes/list.dart';
710
import 'package:parteiduell_backend/version.dart';
811

912
const apiVersion = 8;
@@ -51,14 +54,18 @@ run({bool debug}) async {
5154

5255
print('Downloading file index...');
5356

54-
final listRes = await http
55-
.get('https://api.github.com/repos/Parteiduell/data/contents/wahlomat');
57+
final listRes = await http.get(
58+
Uri.parse(
59+
'https://api.github.com/repos/Parteiduell/data/contents/quizQuestions',
60+
),
61+
);
62+
5663
final list = json.decode(listRes.body);
5764

5865
// Einlesen der Daten
5966
for (final item in list) {
6067
print('Downloading file ${item['name']}...');
61-
final res = await http.get(item['download_url']);
68+
final res = await http.get(Uri.parse(item['download_url']));
6269

6370
quizFragen.addAll(
6471
json.decode(res.body).map<QuizThese>((m) => QuizThese.fromJson(m)));
@@ -84,257 +91,43 @@ run({bool debug}) async {
8491
/* scoreboard = json.decode(
8592
File('/' + __dirname + '/data/db/scoreboard.json').readAsStringSync()); */
8693

94+
// Einrichtung des Servers
95+
final app = Alfred(logLevel: debug ? LogType.debug : LogType.info);
96+
97+
// CORS erlauben
98+
app.all('*', cors(origin: '*'));
99+
100+
// Routen einrichten
101+
102+
app.get('/', (req, res) {
103+
// Redirecten zum Repository, wenn keine Methode angegeben ist.
104+
res.redirect(Uri.https("github.com", "Parteiduell/backend"));
105+
});
106+
107+
// Abrufen von Quizfragen
108+
app.get('/list', handleListRequest);
109+
110+
// Abrufen aller Parteien
111+
app.get('/allParties', handleAllPartiesRequest);
112+
113+
// Abrufen aller Quellen
114+
app.get('/allSources', handleAllSourcesRequest);
115+
116+
app.get('/ping', (req, res) => 'Pong!');
117+
118+
app.get(
119+
'/version',
120+
(req, res) => {
121+
'version': apiVersion,
122+
'apiVersion': apiVersion,
123+
'versionName': versionName,
124+
},
125+
);
126+
87127
// Server Port
88128
var portEnv = Platform.environment['PORT'];
89129
var port = portEnv == null ? 3000 : int.parse(portEnv);
90130

91131
// Starten des Servers
92-
var server = await HttpServer.bind('0.0.0.0', port);
93-
94-
print("Serving at ${server.address}:${server.port}");
95-
96-
// Beantworten jeder Anfrage
97-
await for (var request in server) {
98-
print(
99-
'[${DateTime.now().toIso8601String()}] ${request.method} from ${request.connectionInfo.remoteAddress} at ${request.uri}');
100-
try {
101-
await execute(request);
102-
} catch (e, st) {
103-
print('$e');
104-
print('$st');
105-
request.response.statusCode = HttpStatus.internalServerError;
106-
request.response.close();
107-
}
108-
}
109-
}
110-
111-
saveScoreboard() async {
112-
/* File('/' + __dirname + '/data/db/scoreboard.json')
113-
.writeAsString(json.encode(scoreboard)); */
114-
}
115-
116-
// Bearbeitung der Anfragen
117-
execute(HttpRequest request) async {
118-
HttpResponse response = request.response;
119-
response.headers.contentType =
120-
ContentType("application", "json", charset: "utf-8");
121-
122-
// Setzen von CORS-Headern
123-
response.headers.add('Access-Control-Allow-Origin', '*');
124-
125-
if (request.uri.path == '/') {
126-
if (request.method == 'GET') {
127-
// Redirecten zum Repository, wenn keine Methode angegeben ist.
128-
request.response.redirect(Uri.https("github.com", "Parteiduell/backend"));
129-
} else {
130-
response.statusCode = HttpStatus.methodNotAllowed;
131-
}
132-
} else if (request.uri.path == '/list') {
133-
if (request.method == 'GET') {
134-
//
135-
// Abrufen von Quizfragen
136-
//
137-
138-
// Übergebene Parameter
139-
int count = int.tryParse(request.uri.queryParameters['count'] ?? '') ?? 1;
140-
bool filterWithTag =
141-
(request.uri.queryParameters['filterWithTag'] ?? 'false') == 'true';
142-
String reqParties = request.uri.queryParameters['parties'] ?? '';
143-
String reqSources = request.uri.queryParameters['sources'] ?? '';
144-
145-
String id = request.uri.queryParameters['id'];
146-
147-
List<String> requestedSources = [];
148-
if (reqSources.isNotEmpty) {
149-
requestedSources.addAll(reqSources.split(','));
150-
} else {
151-
requestedSources.addAll(commonSources);
152-
}
153-
154-
// Nicht gewünschte Quellen herausfiltern
155-
List<QuizThese> quizFragenAuswahl = quizFragen
156-
.where((t) => requestedSources.contains(t.context))
157-
.toList();
158-
if (id != null) {
159-
quizFragenAuswahl.retainWhere((t) => t.id == id);
160-
}
161-
quizFragenAuswahl.shuffle();
162-
163-
List<QuizQuestion> questions = [];
164-
165-
// Solange Quizfragen aussuchen, bis die gewünschte Anzahl erreicht oder keine Thesen mehr übrig sind
166-
for (int i = 0; i < count; i++) {
167-
if (i >= quizFragenAuswahl.length) break;
168-
QuizThese these = quizFragenAuswahl[i];
169-
170-
var question = QuizQuestion(
171-
context: these.context, source: these.source, these: these.these);
172-
173-
List<String> parties = these.statements.keys.toList();
174-
175-
// Unbekannte oder nicht angefragte Parteien herausfiltern
176-
List<String> requestedParties = [];
177-
if (reqParties.isNotEmpty) {
178-
requestedParties.addAll(reqParties.split(','));
179-
} else {
180-
requestedParties.addAll(commonParties);
181-
}
182-
parties.removeWhere((p) => !requestedParties.contains(p));
183-
184-
// Entfernen von Parteien, die keine Antwort abgegeben haben
185-
parties.removeWhere((p) => these.statements[p].isEmpty);
186-
debugPrint('Parteien: $parties');
187-
debugPrint('${parties.length}/${requestedParties.length}');
188-
189-
// Wenn weniger als zwei Parteien übrig bleiben, wird eine andere These verwendet
190-
if (parties.length < 2) {
191-
count++;
192-
continue;
193-
}
194-
195-
// Parteien aussuchen und durchmischen
196-
parties.shuffle();
197-
parties = parties.take(4).toList();
198-
199-
question.possibleAnswers = {};
200-
201-
// Generieren der Antwortmöglichkeiten
202-
for (String key in parties) {
203-
String statement = these.statements[key];
204-
if (statement.trim().length == 0)
205-
statement =
206-
'Diese Partei hat keine Erklärung zu dieser These abgegeben.';
207-
208-
question.possibleAnswers[key] = statement;
209-
}
210-
question.possibleParties = parties;
211-
question.theseId = these.id;
212-
213-
questions.add(question);
214-
}
215-
216-
request.response.write(json.encode(questions));
217-
} else {
218-
response.statusCode = HttpStatus.methodNotAllowed;
219-
}
220-
} else if (request.uri.path == '/allParties') {
221-
// Abrufen aller Parteien
222-
if (request.method == 'GET') {
223-
String source = request.uri.queryParameters['sources'] ?? '';
224-
Set<String> sourcePartiesSet = {};
225-
if (source.isEmpty) {
226-
response.write(json.encode(allParties.toList()));
227-
} else {
228-
for (String source in source.split(',')) {
229-
sourcePartiesSet.addAll(sourceParties[source]);
230-
}
231-
response.write(json.encode(sourcePartiesSet.toList()));
232-
}
233-
} else {
234-
response.statusCode = HttpStatus.methodNotAllowed;
235-
}
236-
} else if (request.uri.path == '/allSources') {
237-
// Abrufen aller Quellen
238-
if (request.method == 'GET') {
239-
request.response.write(json.encode(allSources.toList()));
240-
} else {
241-
response.statusCode = HttpStatus.methodNotAllowed;
242-
}
243-
} else if (request.uri.path == '/submitScore') {
244-
if (request.method == 'POST') {
245-
String content = await utf8.decoder.bind(request).join();
246-
var data = json.decode(content);
247-
248-
// Limits
249-
// Name: 20 Chars
250-
// Score: 100
251-
if (data['score'] > 100 || data['score'] < 0) {
252-
response.statusCode = HttpStatus.badRequest;
253-
} else if (data['name'].length > 20 || data['name'].length == 0) {
254-
response.statusCode = HttpStatus.badRequest;
255-
} else {
256-
scoreboard.add({'name': data['name'], 'score': data['score']});
257-
scoreboard.sort((a, b) => -a['score'].compareTo(b['score']));
258-
if (scoreboard.length > 10) {
259-
scoreboard.removeRange(10, scoreboard.length);
260-
}
261-
saveScoreboard();
262-
}
263-
} else {
264-
response.statusCode = HttpStatus.methodNotAllowed;
265-
}
266-
} else if (request.uri.path == '/scoreboard') {
267-
if (request.method == 'GET') {
268-
request.response.write(json.encode(scoreboard));
269-
} else {
270-
response.statusCode = HttpStatus.methodNotAllowed;
271-
}
272-
} else if (request.uri.path == '/ping') {
273-
if (request.method == 'GET') {
274-
request.response.write("Pong!");
275-
} else {
276-
response.statusCode = HttpStatus.methodNotAllowed;
277-
}
278-
} else if (request.uri.path == '/version') {
279-
if (request.method == 'GET') {
280-
request.response.write(json.encode({
281-
'version': apiVersion,
282-
'apiVersion': apiVersion,
283-
'versionName': versionName,
284-
}));
285-
} else {
286-
response.statusCode = HttpStatus.methodNotAllowed;
287-
}
288-
} else if (request.uri.path == '/listMock') {
289-
if (request.method == 'GET') {
290-
request.response.write('''
291-
[
292-
{
293-
"these": "Der Ausbau erneuerbarer Energien soll vom Bund dauerhaft finanziell gefördert werden.",
294-
"possibleAnswers": {
295-
"AfD": "Auch die sogenannten erneuerbaren Energien müssen sich am Markt bewähren. Sie bringen zudem nicht nur Vorteile, sondern auch viele Nachteile mit sich. Die Dauersubventionierung belastet die deutsche Volkswirtschaft in erheblichen Maße. Soweit die Subventionierung über Sonderabgaben erfolgt, wie die die Stromabgabe, entstehen der Wirtschaft Kostennachteile, die zur Verlagerung ganzer Industriezweige ins Ausland führen. Zudem werden die Privathaushalte schon derzeit mit ca. 25 Mrd. durch solche Maßnahmen belastet. Diese Mittel fehlen den Bürgern für den eigenen Lebensbedarf und insbesondere für eine notwendige Altersvorsorge.",
296-
"NPD": "Der Ausbau erneuerbarer Energien ist nicht nur aus Gründen des Umweltschutzes, sondern auch zur Erlangung größerer Unabhängigkeit von Energie-Importen aus dem Ausland grundsätzlich zu begrüßen. Bei der Förderung sollte allerdings ein Schwerpunkt auf die Erforschung geeigneter Speichertechnologien gelegt werden, um eine bessere dezentrale Verfügbarkeit zu erreichen, Energieverluste zu vermeiden und auf gigantische und die Landschaft verschandelnde Windparks verzichten zu können.",
297-
"FDP": "Erneuerbare Energien sind für uns ein wichtiges Element im Energiemix der Zukunft. Auch für die erneuerbaren Energieträger müssen in Zukunft aber die Regeln des Marktes mit allen Chancen und Risiken gelten. Denn nachhaltige und subventionsfreie Geschäftsmodelle lassen sich nur im technologieneutralen Wettbewerb unter marktwirtschaftlichen Bedingungen durchsetzen.",
298-
"DIE LINKE": "Wir wollen den Klimawandel stoppen. Dafür setzen wir auf erneuerbare Energien. █████ will eine echte Energiewende finanzieren, in der die fossilen, umweltschädlichen Energien durch regenerative ersetzt werden. Sie soll bürgernah - v.a. durch Genossenschaften und Stadtwerke - organisiert sein und als Teil der öffentlichen Daseinsvorsorge. Die Verbraucher entlasten wir durch soziale Preisgestaltung und einen Energiewendefonds."
299-
},
300-
"answer": "NPD",
301-
"source": "wahlometer.watch",
302-
"context": "Bundestagswahl 2017",
303-
"statement": "Der Ausbau erneuerbarer Energien ist nicht nur aus Gründen des Umweltschutzes, sondern auch zur Erlangung größerer Unabhängigkeit von Energie-Importen aus dem Ausland grundsätzlich zu begrüßen. Bei der Förderung sollte allerdings ein Schwerpunkt auf die Erforschung geeigneter Speichertechnologien gelegt werden, um eine bessere dezentrale Verfügbarkeit zu erreichen, Energieverluste zu vermeiden und auf gigantische und die Landschaft verschandelnde Windparks verzichten zu können.",
304-
"possibleParties": [
305-
"AfD",
306-
"NPD",
307-
"FDP",
308-
"DIE LINKE"
309-
]
310-
},
311-
{
312-
"these": "Deutschland soll zu einer nationalen Währung zurückkehren.",
313-
"possibleAnswers": {
314-
"Die PARTEI": "Deutschland soll natürlich zu zwei nationalen Währungen zurückkehren, zur D- und zur Ostmarkt. Wir sind zwei Volk!",
315-
"AfD": "Da der Euro gescheitert ist, muss Deutschland entweder mit anderen, ökonomisch zu uns passenden Staaten einen Währungsverbund schaffen oder zur D-Mark zurückkehren. Wir wollen deshalb für die Wiedereinführung einer neuen nationalen Währung rechtzeitige Vorkehrungen treffen. Das im Ausland gelagerte Gold der Bundesbank muss vollständig und umgehend nach Deutschland überführt werden. Bei der Wiedereinführung der Deutschen Mark könnte Deutschland das Gold als temporäre Deckungsoption benötigen.",
316-
"SPD": "Deutschland profitiert vom Euro. Die europäische Währung ist ein integraler Bestandteil des europäischen Projekts, nicht nur in ökonomischer, sondern auch in politischer Hinsicht. Ein Austritt aus dem Euro hätte schwere ökonomische und soziale Verwerfungen zur Folge. Wir sehen erste negative Folgen bereits in Großbritannien durch den Brexit.",
317-
"GRÜNE": "Der Euro ist eine große Errungenschaft für Europa und für Deutschland: er erleichtert den Handel und Zahlungsverkehr. Wichtig ist aber, dass innerhalb des Währungsraums ein solidarischer Ausgleich geschaffen wird und Ungleichgewichte verhindert werden. Die Währungsunion muss fortentwickelt und durch eine gemeinsame Wirtschafts- und Fiskalpolitik ergänzt werden. Ein Austritt eines Mitgliedslands aus dem Euro hätte unabsehbare negative Folgen für Wohlstand und Arbeitsplätze in Deutschland."
318-
},
319-
"answer": "AfD",
320-
"source": "wahlometer.watch",
321-
"context": "Bundestagswahl 2017",
322-
"statement": "Da der Euro gescheitert ist, muss Deutschland entweder mit anderen, ökonomisch zu uns passenden Staaten einen Währungsverbund schaffen oder zur D-Mark zurückkehren. Wir wollen deshalb für die Wiedereinführung einer neuen nationalen Währung rechtzeitige Vorkehrungen treffen. Das im Ausland gelagerte Gold der Bundesbank muss vollständig und umgehend nach Deutschland überführt werden. Bei der Wiedereinführung der Deutschen Mark könnte Deutschland das Gold als temporäre Deckungsoption benötigen.",
323-
"possibleParties": [
324-
"Die PARTEI",
325-
"AfD",
326-
"SPD",
327-
"GRÜNE"
328-
]
329-
}
330-
]
331-
''');
332-
} else {
333-
response.statusCode = HttpStatus.methodNotAllowed;
334-
}
335-
} else {
336-
response.statusCode = HttpStatus.notFound;
337-
}
338-
// Schließen der Verbindung
339-
await response.close();
132+
await app.listen(port);
340133
}

lib/routes/all_parties.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import 'package:alfred/alfred.dart';
2+
import 'package:parteiduell_backend/parteiduell_backend.dart';
3+
4+
dynamic handleAllPartiesRequest(HttpRequest req, HttpResponse res) {
5+
String source = req.uri.queryParameters['sources'] ?? '';
6+
Set<String> sourcePartiesSet = {};
7+
if (source.isEmpty) {
8+
return allParties.toList();
9+
} else {
10+
for (String source in source.split(',')) {
11+
sourcePartiesSet.addAll(sourceParties[source]);
12+
}
13+
return sourcePartiesSet.toList();
14+
}
15+
}

lib/routes/all_sources.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import 'package:alfred/alfred.dart';
2+
import 'package:parteiduell_backend/parteiduell_backend.dart';
3+
4+
dynamic handleAllSourcesRequest(HttpRequest req, HttpResponse res) {
5+
return allSources.toList();
6+
}

0 commit comments

Comments
 (0)