diff --git a/index.js b/index.js index dd8e301..e27ae81 100644 --- a/index.js +++ b/index.js @@ -65,12 +65,12 @@ router.get('/', async ctx => { } try { - const sql = 'SELECT Userid, Category, Title, Summary, Comment, Image FROM Article;' + const sql = 'SELECT id,rtitle,Name,Stars,comment FROM reviews;' const db = await sqlite.open('./website.db') const data = await db.all(sql) await db.close() console.log(data) - await ctx.render('index', {Userid: 'Identification', Category: 'Field of news', Title: 'Heading', Summary: 'Short description', Comment: 'Explanation', Image: 'Title for image', Article: data}) + await ctx.render('index', {id: 'Identification', Name: 'creator name', Stars: 'Rating', Comment: 'message',rTitle : 'Review Title', review: data}) } catch(err) { ctx.body = err.message } @@ -293,10 +293,10 @@ router.get('/upload', async ctx => { }) - +// upload with if statement to see each new in the appropriate category router.post('/upload', koaBody, async ctx => { -// router.post('/upload', async ctx => { + try { const body = ctx.request.body console.log(body) @@ -310,12 +310,71 @@ router.post('/upload', koaBody, async ctx => { await fs.copy(path, `public/articles/${body.image}.png`) const sql = `INSERT INTO Article(Userid, Category, Title, Summary, Comment, Image) VALUES("${body.userid}", "${body.category}", "${body.title}", "${body.summary}", "${body.comment}", "${body.image}");` - await db.run(sql) + await db.run(sql) + if(body.category == 'Business'){ // Category Business + + const sql = 'SELECT Userid, Category, Title, Summary, Comment, Image FROM Article Where Category="Business";' + const db = await sqlite.open('./website.db') + const data = await db.all(sql) await db.close() - return ctx.redirect('/upload?successMsg=You have successfully uploaded!') - } catch(err) { + console.log(data) + await ctx.render('Business', {Userid: 'Identification', Category: 'Field of news', Title: 'Heading', Summary: 'Short description', Comment: 'Explanation', Image: 'Title for image', Business: data}) + + + + }else if(body.category == 'Music'){ // Category Music + + const sql = 'SELECT Userid, Category, Title, Summary, Comment, Image FROM Article Where Category="Music";' + const db = await sqlite.open('./website.db') + const data = await db.all(sql) + console.log(data) + await db.close() + await ctx.render('Music', {Userid: 'Identification', Category: 'Field of news', Title: 'Heading', Summary: 'Short description', Comment: 'Explanation', Image: 'Title for image', Music: data}) + + + }else if(body.category == 'Entertainment'){ // Category Entertainment + + const sql = 'SELECT Userid, Category, Title, Summary, Comment, Image FROM Article Where Category="Entertainment";' + const db = await sqlite.open('./website.db') + const data = await db.all(sql) + console.log(data) + await db.close() + await ctx.render('entertainment', {Userid: 'Identification', Category: 'Field of news', Title: 'Heading', Summary: 'Short description', Comment: 'Explanation', Image: 'Title for image', enter: data}) + + + }else if(body.category == 'Careers'){ // Category careers + + const sql = 'SELECT Userid, Category, Title, Summary, Comment, Image FROM Article Where Category="Careers";' + const db = await sqlite.open('./website.db') + const data = await db.all(sql) + console.log(data) + await db.close() + await ctx.render('careers', {Userid: 'Identification', Category: 'Field of news', Title: 'Heading', Summary: 'Short description', Comment: 'Explanation', Image: 'Title for image', careers: data}) + + }else if(body.category == 'Sports'){ // Category sports + + const sql = 'SELECT Userid, Category, Title, Summary, Comment, Image FROM Article Where Category="Sports";' + const db = await sqlite.open('./website.db') + const data = await db.all(sql) + console.log(data) + await db.close() + await ctx.render('sports', {Userid: 'Identification', Category: 'Field of news', Title: 'Heading', Summary: 'Short description', Comment: 'Explanation', Image: 'Title for image', sports: data}) + + }else if(body.category == 'Life_And_Style'){ // Category Life & Style + + const sql = 'SELECT Userid, Category, Title, Summary, Comment, Image FROM Article Where Category="Life_And_Style";' + const db = await sqlite.open('./website.db') + const data = await db.all(sql) + console.log(data) + await db.close() + await ctx.render('lifeandstyle', {Userid: 'Identification', Category: 'Field of news', Title: 'Heading', Summary: 'Short description', Comment: 'Explanation', Image: 'Title for image', life: data}) + } + + + }catch(err) { await ctx.render('error', {message: err.message}) } + }) @@ -324,7 +383,9 @@ router.post('/upload', koaBody, async ctx => { const data = {} data.user = ctx.session.user await ctx.render('reviews', data) - }) + }); + + router.post('/reviews', async ctx => { @@ -332,9 +393,9 @@ router.post('/upload', koaBody, async ctx => { console.log(ctx.request.body) const body = ctx.request.body const db = await sqlite.open('./website.db') - await db.run('CREATE TABLE IF NOT EXISTS reviews (id INTEGER PRIMARY KEY AUTOINCREMENT,Name TEXT, Stars integer, comment TEXT);') - const sql = `INSERT INTO reviews (Name, stars, comment) - VALUES("${body.name}", "${body.stars}", "${body.comment}");` + await db.run('CREATE TABLE IF NOT EXISTS reviews (id INTEGER PRIMARY KEY AUTOINCREMENT,Name TEXT, Stars integer, comment TEXT, rTitle Text);') + const sql = `INSERT INTO reviews (Name, stars, comment, rTitle) + VALUES("${body.name}", "${body.stars}", "${body.comment}","${body.rTitle}");` await db.run(sql) await db.close() return ctx.redirect('/reviews?successMsg=You have successfully uploaded!') diff --git a/lifeandstyle.css b/lifeandstyle.css new file mode 100644 index 0000000..91314b9 --- /dev/null +++ b/lifeandstyle.css @@ -0,0 +1,204 @@ +.navbar { + overflow: hidden; + background-color: #000033; + +} + +.navbar a { + float: left; + display: block; + color: white; + text-align: center; + padding: 14px 20px; + text-decoration: none; + +} + +.navbar a.right { + float: right; + +} + +.navbar a:hover { + background-color: #ddd; + color: black; +} +.navbar input[type=text] { + float: right; + padding: 6px; + border: none; + margin-top: 8px; + margin-right: 16px; + font-size: 17px; +} + +.header { + text-align: center; + background: linear-gradient(to bottom, #ff6600 0%, #ffff00 100%); + color: #000033; + +} + +body { + margin: 0; + font-family: Arial, Helvetica, sans-serif; + background-color: #ffff99 + + +} + +.sidenav { + height: 100%; + width: 200px; + position: absolute; + z-index: 1; + top: 0; + left: 0; + background-image: url(/images/business.png); + background-repeat: no-repeat bottom; + overflow-x: hidden; + overflow-y: hidden; + margin-top: 49px; + margin-bottom: -5000px; + padding-bottom: 5000px; + +} + + +.sidenav a { + color: white; + padding: 14px 20px; + text-decoration: none; + display: block; + + +} + +.sidenav a:hover { + background: #ddd; + color: black; +} + + +.content { + margin-left: 200px; + padding-left: 20px; + color: #000033; +} + +.main { + margin-right: auto; + position:relative; + font-size: 20px; + padding: 0px 10px; +} +.column { + float: left; + width: 33.33%; + padding: 5px; +} +.column:after { + content: ""; + display: table; + clear: both; +} + + +* { + box-sizing: border-box; +} + + +.mySlides {display: none} +img {vertical-align: middle;} + +.slideshow-container { + max-width: 1000px; + position: relative; + margin: auto; +} + +.prev, .next { + cursor: pointer; + position: absolute; + top: 50%; + width: auto; + padding: 16px; + margin-top: -22px; + color: #000033; + font-weight: bold; + font-size: 18px; + transition: 0.6s ease; + border-radius: 0 3px 3px 0; + user-select: none; +} + + +.next { + right: 0; + border-radius: 3px 0 0 3px; +} + + +.prev:hover, .next:hover { + background-color: rgba(0,0,0,0.8); +} + +.text { + color: #f2f2f2; + font-size: 15px; + padding: 8px 12px; + position: absolute; + bottom: 8px; + width: 100%; + text-align: center; +} + + +.numbertext { + color: #f2f2f2; + font-size: 12px; + padding: 8px 12px; + position: absolute; + top: 0; +} + + +.dot { + cursor: pointer; + height: 15px; + width: 15px; + margin: 0 2px; + background-color: #bbb; + border-radius: 50%; + display: inline-block; + transition: background-color 0.6s ease; +} + +.active, .dot:hover { + background-color: #717171; +} + + +.fade { + -webkit-animation-name: fade; + -webkit-animation-duration: 1.5s; + animation-name: fade; + animation-duration: 1.5s; +} + +@-webkit-keyframes fade { + from {opacity: .4} + to {opacity: 1} +} + +@keyframes fade { + from {opacity: .4} + to {opacity: 1} +} + +/* On smaller screens, decrease text size */ +@media only screen and (max-width: 300px) { + .prev, .next,.text {font-size: 11px} +} + diff --git a/modules/register.js b/modules/register.js new file mode 100644 index 0000000..bdb58a1 --- /dev/null +++ b/modules/register.js @@ -0,0 +1,53 @@ +'use strict' + +var sqlite = require('sqlite-async'); +let bcrypt = require('bcrypt-promise'); + +async function runSQL(query) { + try { + console.log(query) + let DBName = "./website.db"; + const db = await sqlite.open(DBName); + const data = await db.all(query); + await db.close(); + if(data.length === 1) return data[0] + return data; + } catch(err) { + throw err + } + +} + +module.exports = class register { + + constructor(dbName = ':memory:') { + return (async() => { + this.db = await sqlite.open(dbName) + const sql = ('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, user TEXT, pass TEXT);') + await this.db.run(sql) + return this + })() + } + + + async checkregister(user,pass) { + try { + if(user.length === 0) throw new Error('Field Required') + if(pass.length === 0) throw new Error('Field Required') + let sql = `SELECT COUNT(id) as records FROM users WHERE user="${user}";` + const data = await this.db.get(sql) + if(data.records !== 0) throw new Error(`users "${user}" already exists`) + sql = `INSERT INTO users(user,pass) VALUES("${user}","${pass}")` + await this.db.run(sql) + return true + } catch(err) { + throw err + } + } + + + } + + + + diff --git a/modules/upload.js b/modules/upload.js new file mode 100644 index 0000000..24d19d9 --- /dev/null +++ b/modules/upload.js @@ -0,0 +1,55 @@ +'use strict' + +var sqlite = require('sqlite-async'); + + +async function runSQL(query) { + try { + console.log(query) + let DBName = "./website.db"; + const db = await sqlite.open(DBName); + const data = await db.all(query); + await db.close(); + if(data.length === 1) return data[0] + return data; + } catch(err) { + throw err + } + +} + +module.exports = class uploadart { + + constructor(dbName = ':memory:') { + return (async() => { + this.db = await sqlite.open(dbName) + const sql = ('CREATE TABLE IF NOT EXISTS Article (First_Name TEXT PRIMARY KEY, Last_name TEXT, Category TEXT ,Title TEXT, Text TEXT)') + await this.db.run(sql) + return this + })() + } + + + async checkarticle(First_Name,Last_name,Category,Title,Text) { + try { + if(First_Name.length === 0) throw new Error('Field Required') + if(Last_name.length === 0) throw new Error('Field Required') + if(Title.length === 0) throw new Error('Field Required') + if(Text.length === 0) throw new Error('Field Required') + let sql = `SELECT COUNT(First_Name) as records FROM Article WHERE First_Name="${First_Name}";` + const data = await this.db.get(sql) + if(data.records !== 0) throw new Error(`Article "${First_Name}" already exists`) + sql = `INSERT INTO Article(First_Name, Last_name, Category ,Title, Text) VALUES("${First_Name}", "${Last_name}", "${Category}" , "${Title}", "${Text}")` + await this.db.run(sql) + return true + } catch(err) { + throw err + } + } + + + } + + + + diff --git a/public/css/business.css b/public/css/business.css index 849e0a7..1649af3 100644 --- a/public/css/business.css +++ b/public/css/business.css @@ -59,6 +59,22 @@ body { } + .card { + + box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); + transition: 0.3s; + } + + + .card:hover { + box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2); + } + + + .container { + padding: 2px 16px; + } + .sidenav a { color: white; diff --git a/public/css/careers.css b/public/css/careers.css index 849e0a7..6b5ecef 100644 --- a/public/css/careers.css +++ b/public/css/careers.css @@ -19,6 +19,22 @@ } +.card { + + box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); + transition: 0.3s; +} + + +.card:hover { + box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2); +} + + +.container { + padding: 2px 16px; +} + .navbar a:hover { background-color: #ddd; color: black; diff --git a/public/css/entertainment.css b/public/css/entertainment.css index 849e0a7..ac8b398 100644 --- a/public/css/entertainment.css +++ b/public/css/entertainment.css @@ -19,6 +19,17 @@ } +.card { + box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); + transition: 0.3s; +} +.card:hover { + box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2); +} +.container { + padding: 2px 16px; +} + .navbar a:hover { background-color: #ddd; color: black; diff --git a/public/css/homepage.css b/public/css/homepage.css index 876dc96..b1c2beb 100644 --- a/public/css/homepage.css +++ b/public/css/homepage.css @@ -126,6 +126,45 @@ a.logout{ } +.boxed { + width: 320px; + padding: 10px; + border: 5px solid gray; ; +} + +.b { + display: inline-block; + position: center; + margin: 10%; + float: left; + height: 400px 3; + background-color: lightgrey; +} +.column3 { + column-rule-style: solid; + width: 100%; + column-count: 2; + + + background-color: lightgrey; + columns: 100px 1; + +} + +table, th, td { + position: left; + table-layout: fixed; + width: 100%; + border: 1px solid grey; + background-color: lightgrey; + text-align: left; + border-collapse: collapse + +} + + + + section2 { float: left; width: 25%; diff --git a/public/css/lifeandstyle.css b/public/css/lifeandstyle.css index 849e0a7..6b5ecef 100644 --- a/public/css/lifeandstyle.css +++ b/public/css/lifeandstyle.css @@ -19,6 +19,22 @@ } +.card { + + box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); + transition: 0.3s; +} + + +.card:hover { + box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2); +} + + +.container { + padding: 2px 16px; +} + .navbar a:hover { background-color: #ddd; color: black; diff --git a/public/css/music.css b/public/css/music.css index 849e0a7..78015e1 100644 --- a/public/css/music.css +++ b/public/css/music.css @@ -13,6 +13,21 @@ text-decoration: none; } +.card { + /* Add shadows to create the "card" effect */ + box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); + transition: 0.3s; +} + +/* On mouse-over, add a deeper shadow */ +.card:hover { + box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2); +} + +/* Add some padding inside the card container */ +.container { + padding: 2px 16px; +} .navbar a.right { float: right; diff --git a/public/css/sports.css b/public/css/sports.css index 849e0a7..6b5ecef 100644 --- a/public/css/sports.css +++ b/public/css/sports.css @@ -19,6 +19,22 @@ } +.card { + + box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); + transition: 0.3s; +} + + +.card:hover { + box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2); +} + + +.container { + padding: 2px 16px; +} + .navbar a:hover { background-color: #ddd; color: black; diff --git a/tests/unit/index.specx.js b/tests/unit/index.specx.js deleted file mode 100644 index 93f7ad4..0000000 --- a/tests/unit/index.specx.js +++ /dev/null @@ -1,33 +0,0 @@ - -'use strict' - -const request = require('supertest') -const status = require('http-status-codes') - -const server = require('../../index.js') - -beforeAll( async() => console.log('Jest starting!')) - -describe('GET /', () => { - // TODO -}) - -describe('GET /register', () => { - // TODO -}) - -describe('POST /register', () => { - // TODO -}) - -describe('GET /login', () => { - // TODO -}) - -describe('POST /login', () => { - // TODO -}) - -describe('GET /logout', () => { - // TODO -}) diff --git a/tests/unit/accounts.spec.js b/tests/unit/login.spec.js similarity index 56% rename from tests/unit/accounts.spec.js rename to tests/unit/login.spec.js index ac9ff3a..92bec59 100644 --- a/tests/unit/accounts.spec.js +++ b/tests/unit/login.spec.js @@ -2,22 +2,6 @@ 'use strict' const accounts = require('../../modules/accounts.js') -//jest.mock('sqlite-async') - -beforeAll( async() => { - console.log('Jest starting!') - // we insert a single user into the database - const sqlite = require('sqlite-async') - const bcrypt = require('bcrypt-promise') - const pass = await bcrypt.hash('goodPassword', 10) - const db = await sqlite.open('./website.db') - await db.run('DROP TABLE IF EXISTS users;') - await db.run('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, user TEXT, pass TEXT);') - console.log(`INSERT INTO users(user, pass) VALUES("jdoe", "${pass}"`) - await db.run(`INSERT INTO users(user, pass) VALUES("jdoe", "${pass}")`) - await db.close() - console.log('database built') -}) describe('checkCredentials()', () => { test('returns true if valid username and password', async done => { @@ -36,7 +20,7 @@ describe('checkCredentials()', () => { expect.assertions(1) try { await accounts.checkCredentials('johndoe', 'goodPassword') - //expect(result).toBe(true) + } catch(err) { expect(err.message).toBe('invalid username') } finally { @@ -48,7 +32,6 @@ describe('checkCredentials()', () => { expect.assertions(1) try { await accounts.checkCredentials('jdoe', 'badPassword') - //expect(result).toBe(true) } catch(err){ expect(err.message).toBe('invalid password') } finally { diff --git a/tests/unit/register.spec.js b/tests/unit/register.spec.js new file mode 100644 index 0000000..fd37c24 --- /dev/null +++ b/tests/unit/register.spec.js @@ -0,0 +1,34 @@ + +const register = require('../../modules/register.js') + +describe('checkregister', () => { + + test('returns true register fields are filled', async done => { + expect.assertions(1) + const reg = await new register() + const checkregister = await reg.checkregister('john','password') + expect(checkregister).toBe(true) + done() + + }) + + + test('Error if no user given', async done => { + expect.assertions(1) + const reg = await new register() + await expect(reg.checkregister('','password')) + .rejects.toEqual(Error('Field Required')) + done() + }) + + + test('Error if no password given', async done => { + expect.assertions(1) + const reg = await new register() + await expect(reg.checkregister('john','')) + .rejects.toEqual(Error('Field Required')) + done() + }) + + +}) \ No newline at end of file diff --git a/tests/unit/upload.spec.js b/tests/unit/upload.spec.js new file mode 100644 index 0000000..9c47fa4 --- /dev/null +++ b/tests/unit/upload.spec.js @@ -0,0 +1,47 @@ + +const uploadart = require('../../modules/upload.js') + +describe('checkarticledb', () => { + + test('returns true if fields from Article db are all filled', async done => { + expect.assertions(1) + const upload = await new uploadart() + const checkarticle = await upload.checkarticle('john', 'Doe','Brexit','idk','Leaving EU') + expect(checkarticle).toBe(true) + done() + + }) + + test('Error if no First_Name given', async done => { + expect.assertions(1) + const upload = await new uploadart() + await expect(upload.checkarticle('', 'Doe', 'Brexit', 'idk', 'Leaving EU')) + .rejects.toEqual(Error('Field Required')) + done() + }) + + test('Error if no Last_name given', async done => { + expect.assertions(1) + const upload = await new uploadart() + await expect(upload.checkarticle('John', '', 'Brexit', 'idk', 'Leaving EU')) + .rejects.toEqual(Error('Field Required')) + done() + }) + test('Error if no Title given', async done => { + expect.assertions(1) + const upload = await new uploadart() + await expect(upload.checkarticle('John', 'Doe', 'Brexit', '', 'Leaving EU')) + .rejects.toEqual(Error('Field Required')) + done() + }) + test('Error if no Text given', async done => { + expect.assertions(1) + const upload = await new uploadart() + await expect(upload.checkarticle('John', '', 'Brexit', 'idk', '')) + .rejects.toEqual(Error('Field Required')) + + done() + }) +}) + + diff --git a/views/business.handlebars b/views/business.handlebars index 59868df..9db9c41 100644 --- a/views/business.handlebars +++ b/views/business.handlebars @@ -25,15 +25,45 @@
- Link + Link Link
-

▶ TOP BUSINESS NEWS

-
-
+

▶ TOP BUSINESS NEWS

+ +
+
+ + {{#each Business}} +
+
+

{{this.Title}}

+
Created by: {{this.Userid}}
+
Category: {{this.Category}}
+ +

Summary: {{this.Summary}}

+
+

{{this.Comment}}

+ +
+
+ + {{/each}} + +
+ + + + + + + + + + + diff --git a/views/careers.handlebars b/views/careers.handlebars index 497ef37..0bd3495 100644 --- a/views/careers.handlebars +++ b/views/careers.handlebars @@ -31,8 +31,26 @@

▶ TOP CAREERS NEWS

-
-
+
+
+ + {{#each careers}} +
+
+

{{this.Title}}

+
Created by: {{this.Userid}}
+
Category: {{this.Category}}
+ +

Summary: {{this.Summary}}

+
+

{{this.Comment}}

+ +
+
+ + {{/each}} + +
diff --git a/views/entertainment.handlebars b/views/entertainment.handlebars index dfc624d..64b34c6 100644 --- a/views/entertainment.handlebars +++ b/views/entertainment.handlebars @@ -31,8 +31,26 @@

▶ TOP ENTERTAINMENT NEWS

-
-
+
+
+ + {{#each enter}} +
+
+

{{this.Title}}

+
Created by: {{this.Userid}}
+
Category: {{this.Category}}
+ +

Summary: {{this.Summary}}

+
+

{{this.Comment}}

+ +
+
+ + {{/each}} + +
diff --git a/views/index.handlebars b/views/index.handlebars index 0d1f0f0..599c25d 100644 --- a/views/index.handlebars +++ b/views/index.handlebars @@ -166,25 +166,35 @@ function showSlides(n) { } -
-
-

User Articles

+ +
+

Reviews

+ + {{#each review}} + + + + + + +
+
+ +
Title: {{this.rTitle}}
+
Rating: {{this.Stars}}
+
Created by : {{this.Name}}
+
Commentary : {{this.comment}}
+ + + + {{/each}} + +
+ + +

-

-
Click here to read all user articles
-
-
- {{#each Article}} - -
Created by: {{this.Userid}}
-

Title: {{this.Title}}

-

Summary:

-

{{this.Summary}}

-
- {{/each}} -
-