Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
bf16fda
Added GUI to add polls
May 14, 2023
2595d9a
database part adapted to task
May 17, 2023
83a6984
Frontend roughly adjusted and prepared for further adjustments for ba…
May 17, 2023
a4dbb28
GET part of services poll and vote adjusted and fed with database query
May 17, 2023
2e69c6f
Routes adapted for the navigation bar in App.vue for the new components
May 17, 2023
977091e
Package.json+yarn.lock...
May 17, 2023
6c27f8b
Merge branch 'mane' into develop
felixdngrs May 17, 2023
dda7cdf
adjustet .sql (Relationships between tables adjusted)
May 18, 2023
96ca6a5
GET (vote) further adapted so that the response object corresponds to…
May 18, 2023
d5797d4
Removed a logic error in the test data
May 19, 2023
7ec9e10
Now the options selected by the user are highlighted in green and are…
May 19, 2023
9df4702
Merge branch 'develop' of https://github.com/luckydonald-learning/pol…
May 19, 2023
cdb44de
Now the options selected by the user are highlighted in green and ar…
May 19, 2023
b6b34c6
The 'Change Vote' button now can only be clicked if the number of opt…
May 19, 2023
3ab33cb
GET written in poll.js and adapted to the required response object
May 19, 2023
47e2bb0
imports etc. adapted for ES in vote.js
May 19, 2023
ee57865
nothing
May 20, 2023
284be99
nothing
May 20, 2023
8c2349e
nothing
May 20, 2023
343cfbb
POST method implemented in Poll.js
May 20, 2023
03e0a57
Polls can now be created and are stored in the database. Tokens are d…
May 20, 2023
f2caa2d
Polls can now be displayed via Share Token to vote. Entering in the A…
May 20, 2023
a028d76
Votes can now be displayed with an edit token. Update option is still…
May 20, 2023
48f9cd8
yarn.lock update etc.
May 20, 2023
89d82da
yarn.lock update etc.
May 20, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@
"devDependencies": {
"swagger-node-codegen": "^1.6.3"
},
"type": "module"
"type": "module"
}
1 change: 0 additions & 1 deletion backend/src/api/routes/poll.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ router.get('/lack/:token', async (req, res, next) => {
const options = {
token: req.params['token']
};

try {
const result = await poll.findPollack(options);
res.status(result.status || 200).send(result.data);
Expand Down
276 changes: 190 additions & 86 deletions backend/src/api/services/poll.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,70 @@
import ServerError from "../../lib/error.js";
import getDatabase from "../../lib/database.js";
import pool from '../../../../database/db.js'; // Anbindung der Datenbank
import ServerError from '../../lib/error.js';
import { uuidv7 } from 'uuidv7';


// Generiere eine UUID7
const generateUUID7 = () => {
const uuid = uuidv7();
return uuid;
};

/**
* Add a new poll.
* @param {Object} options
* @throws {Error}
* @return {Promise}
*/
export async function addPollack(options) {
// Implement your business logic here...
//
// This function should return as follows:
//
// return {
// status: 200, // Or another success code.
// data: [] // Optional. You can put whatever you want here.
// };
//
// If an error happens during your business logic implementation,
// you should throw an error as follows:
//
// throw new ServerError({
// status: 500, // Or another error code.
// error: 'Server Error' // Or another error message.
// });
export const addPollack = async (options) => {
const title = options.body.title;
const description = options.body.description;
const voices = options.body.setting.voices;
const worst = options.body.setting.worst;
const deadline = (options.body.setting.deadline) === '' ? undefined : (options.body.setting.deadline);
const polloptions = options.body.options;

const insertPoll = await pool.query(
`INSERT INTO "poll" ("title", "description", "voices", "worst", "deadline")
VALUES ($1, $2, $3, $4, $5);`,
[title, description, voices, worst, deadline]
);

const latestPollIDQuery = await pool.query(`SELECT COUNT(*) AS row_count FROM "poll";`);
const latestPollIDNum = parseInt(latestPollIDQuery.rows[0].row_count);

// Generiere share- und admin-token
const uuid7_share = generateUUID7();
const uuid7_admin = generateUUID7();

const insertPollToken = await pool.query(
`INSERT INTO "polltoken" ("admin", "share", "poll") VALUES ($1, $2, $3);`,
[uuid7_admin, uuid7_share, latestPollIDNum]
);

// Füge alle Optionen hinzu
for (const option of polloptions) {
const optionText = option.text;
const insertPollOption = await pool.query(`INSERT INTO "polloption" ("text", "poll") VALUES ($1, $2);`, [
optionText,
latestPollIDNum
]);
}

return {
status: 200,
data: 'addPollack ok!'
data: {
admin: {
link: "",
value: uuid7_admin
},
share: {
link: "",
value: uuid7_share
}
}
};
}
};


/**
* Return the statistics of the poll by share token.
Expand All @@ -39,100 +74,169 @@ export async function addPollack(options) {
* @throws {Error}
* @return {Promise}
*/
export async function findPollack(options) {
// Implement your business logic here...
//
// This function should return as follows:
//
// return {
// status: 200, // Or another success code.
// data: [] // Optional. You can put whatever you want here.
// };
//
// If an error happens during your business logic implementation,
// you should throw an error as follows:
//
// throw new ServerError({
// status: 500, // Or another error code.
// error: 'Server Error' // Or another error message.
// });
const { token } = options;

export const findPollack = async (options) => {

try {
const db = await getDatabase();
// const res = await db.query('SELECT $1::text as message', ['Hello world!'])
const res = await db.query('SELECT * FROM "poll" WHERE token = $1::UUID', [token])
console.log(res.rows[0]) // Hello world!
await db.end()
} catch (e) {
console.error(e); // TODO: better error handling, yo.
const pollack = await pool.query(`SELECT p.*
FROM poll AS p
JOIN polltoken AS pt ON p.id = pt.poll
WHERE pt.share = $1;
`, [options.token]);

if (!pollack) {
throw new Error('Pollack not found');
}

const pollRow = pollack.rows[0];

const allOptions = await pool.query(`SELECT po.id, po.text, po.fixed
FROM polltoken AS pt
JOIN poll AS p ON pt.poll = p.id
JOIN polloption AS po ON p.id = po.poll
WHERE pt.share = $1;`, [options.token]);

// Fasse alle Optionen zu einem Array wie im Response gefordert zusammen
const optionsArray = allOptions.rows.map(row => ({
id: row.id,
text: row.text
}));

const participants = await pool.query(`SELECT u.*
FROM "user" AS u
JOIN poll_user AS pu ON u.id = pu.user
WHERE pu.poll = $1;`, [pollRow.id]);

// Fasse alle Optionen zu einem Array wie im Response gefordert zusammen
const participantsArray = participants.rows.map(row => ({
name: row.name,
}));

const voicesOfPoll = await pool.query(`SELECT pv.polloption, ARRAY_AGG(v.owner) AS user_ids
FROM polloption_vote AS pv
JOIN vote AS v ON pv.vote = v.id
WHERE v.poll = $1
GROUP BY pv.polloption;`, [pollRow.id]);

const voicesOfPollArray = voicesOfPoll.rows.map(row => ({
polloption: row.polloption,
user_ids: row.user_ids,
}));

// Array mit den IDs der PollOptions, bei denen fixed=true ist
const fixedOptions = allOptions.rows
.filter(option => option.fixed === true)
.map(option => option.id);


const optionsWrapper = { options: [] };

for (const option of optionsArray) {
const optionId = option.id;
const optionText = option.text;
const userIds = [];

// Überprüfen, ob die Option im Ergebnis der SELECT-Anweisung enthalten ist
for (const row of voicesOfPollArray) {
if (row.polloption === String(optionId)) {
userIds.push(...row.user_ids);
break;
}
}
const optionData = {
voted: userIds,
worst: []
};
optionsWrapper.options.push(optionData);
}

const response = {
"poll": {
"body": {
"title": pollRow.title,
"description": pollRow.description,
"options": optionsArray,
"setting": {
"voices": pollRow.voices,
"worst": pollRow.worst,
"deadline": pollRow.deadline,
},
"fixed": fixedOptions,
},
"share": {
"link": "string",
"value": options.token,
}
},
"participants": participantsArray,
"options": optionsWrapper.options,
}

return {
status: 200,
data: response,
};
} catch (error) {
throw new ServerError({
status: 500,
error: error.message
});
}
};


return {
status: 200,
data: 'findPollack ok!'
};
}

/**
* @param {Object} options
* @param {String} options.token Admin token to perform the update with
* @throws {Error}
* @return {Promise}
*/
export async function updatePollack(options) {
// Implement your business logic here...
//
// This function should return as follows:
//
// return {
// status: 200, // Or another success code.
// data: [] // Optional. You can put whatever you want here.
// };
//
// If an error happens during your business logic implementation,
// you should throw an error as follows:
//
// throw new ServerError({
// status: 500, // Or another error code.
// error: 'Server Error' // Or another error message.
// });
export const updatePollack = async (options) => {
const tokensFound = await pool.query(`SELECT COUNT(*) AS token_count
FROM polltoken
WHERE admin = $1;
`, [options.token]);

console.log("FOUND:" + JSON.stringify(tokensFound));
if (!tokensFound) {
throw new Error('Pollack not found');
}

return {
status: 200,
data: 'updatePollack ok!'
};
}


const countAdminTokens = async (adminToken) => {
const tokensFound = await pool.query(`SELECT COUNT(*) AS token_count
FROM polltoken
WHERE admin = $1;
`, [adminToken]);

console.log("FOUND:" + JSON.stringify(tokensFound));
return tokensFound;
}

/**
* @param {Object} options
* @param {String} options.token Admin token to delete the poll
* @throws {Error}
* @return {Promise}
*/
export async function deletePollack(options) {
// Implement your business logic here...
//
// This function should return as follows:
//
// return {
// status: 200, // Or another success code.
// data: [] // Optional. You can put whatever you want here.
// };
//
// If an error happens during your business logic implementation,
// you should throw an error as follows:
//
// throw new ServerError({
// status: 500, // Or another error code.
// error: 'Server Error' // Or another error message.
// });
export const deletePollack = async (options) => {
const tokensFound = countAdminTokens(options.token) > 0;
if (!tokensFound) {
throw new Error('Pollack not found');
}

return {
status: 200,
data: 'deletePollack ok!'
};
}

export default {addPollack, findPollack, updatePollack, deletePollack}
export default { addPollack, findPollack, updatePollack, deletePollack }

Loading