Skip to content

Commit 08616b7

Browse files
committed
initial commit
0 parents  commit 08616b7

35 files changed

+28683
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.DS_Store
2+
node_modules

backend/.eslintrc.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
module.exports = {
2+
"env": {
3+
"commonjs": true,
4+
"es6": true,
5+
"node": true
6+
},
7+
"extends": [
8+
"standard"
9+
],
10+
"globals": {
11+
"Atomics": "readonly",
12+
"SharedArrayBuffer": "readonly"
13+
},
14+
"parserOptions": {
15+
"ecmaVersion": 2018
16+
},
17+
"rules": {
18+
}
19+
};

backend/Dockerfile

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
FROM node:10-alpine
2+
3+
RUN mkdir -p /src
4+
5+
COPY package.json src/package.json
6+
7+
WORKDIR /src
8+
9+
RUN npm install --only=production --silent
10+
11+
COPY . /src
12+
13+
CMD npm start

backend/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
## Backend do curso treinamento de Vue.js 3
2+
3+
Backend pré-pronto do curso treinamento de Vue.js 3
4+
5+
### Comandos
6+
7+
```
8+
# Buildar o backend em um container do docker
9+
npm run build
10+
11+
# Rodar o container que foi buildado
12+
npm run container
13+
14+
# O backend estará disponível na porta 3000
15+
```
16+
17+
_Este backend existe para auxiliar o curso de front-end com [Vue.js 3 do Vue.js Brasil](https://treinamento.vuejsbrasil.org/)_
18+

backend/database/index.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
const database = require('./mock')
2+
3+
function wait (timeMs) {
4+
return new Promise(resolve => {
5+
setTimeout(resolve, timeMs)
6+
})
7+
}
8+
9+
async function update (col, id, data) {
10+
if (!database[col]) {
11+
return false
12+
}
13+
14+
database[col] = database[col].map(item => {
15+
if (item.id === id) {
16+
return { ...item, ...data }
17+
}
18+
19+
return item
20+
})
21+
22+
await wait(500)
23+
return true
24+
}
25+
26+
async function readAll (col) {
27+
await wait(2500)
28+
if (!database[col]) {
29+
return []
30+
}
31+
32+
return database[col].sort((a, b) => b.createdAt - a.createdAt)
33+
}
34+
35+
async function insert (col, data) {
36+
if (!database[col]) {
37+
database[col] = []
38+
}
39+
40+
database[col].push(data)
41+
await wait(500)
42+
return true
43+
}
44+
45+
async function readOneById (col, id) {
46+
if (!database[col]) return
47+
const res = database[col].find(item => String(item.id) === String(id))
48+
49+
await wait(500)
50+
return res
51+
}
52+
53+
async function readOneByEmail (col, email) {
54+
if (!database[col]) return
55+
const res = database[col].find(item => String(item.email) === String(email))
56+
57+
await wait(500)
58+
return res
59+
}
60+
61+
module.exports = {
62+
update,
63+
insert,
64+
readAll,
65+
readOneById,
66+
readOneByEmail
67+
}

backend/database/mock.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
module.exports = {
2+
users: [
3+
{
4+
id: 'eab759f8-f238-4ff9-ae91-ee1558982329',
5+
name: 'Igor Halfeld',
6+
7+
password: '1234',
8+
apiKey: 'fcd5015c-10d3-4e9c-b395-ec7ed8850165',
9+
createdAt: new Date('2020-09-05').getTime()
10+
}
11+
],
12+
feedbacks: [
13+
{
14+
text: 'Muito bom!',
15+
fingerprint: '490135491',
16+
id: 'eab759f8-f238-4ff9-ae91-ee1558982329',
17+
apiKey: 'fcd5015c-10d3-4e9c-b395-ec7ed8850165',
18+
type: 'OTHER',
19+
device: 'Chrome 85.0, macOS 10.14',
20+
page: 'https://feedbacker.com/pricing',
21+
createdAt: new Date('2020-11-13').getTime()
22+
},
23+
{
24+
text: 'Muitos erros slkkkkkkk',
25+
fingerprint: '490135491',
26+
id: 'eab759f8-f238-4ff9-ae91-ee1558982329',
27+
apiKey: 'fcd5015c-10d3-4e9c-b395-ec7ed8850165',
28+
type: 'ISSUE',
29+
device: 'Chrome 85.0, macOS 10.14',
30+
page: 'https://feedbacker.com/pricing',
31+
createdAt: new Date('2020-10-23').getTime()
32+
},
33+
{
34+
text: 'Podia ter um botão de solicitar demo',
35+
fingerprint: '490135491',
36+
id: 'eab759f8-f238-4ff9-ae91-ee1558982329',
37+
apiKey: 'fcd5015c-10d3-4e9c-b395-ec7ed8850165',
38+
type: 'IDEA',
39+
device: 'Chrome 85.0, macOS 10.14',
40+
page: 'https://feedbacker.com/pricing',
41+
createdAt: new Date('2020-09-23').getTime()
42+
},
43+
{
44+
text: 'Podia ter um botão de solicitar demo 1',
45+
fingerprint: '490135491',
46+
id: 'eab759f8-f238-4ff9-ae91-ee1558982329',
47+
apiKey: 'fcd5015c-10d3-4e9c-b395-ec7ed8850165',
48+
type: 'IDEA',
49+
device: 'Chrome 85.0, macOS 10.14',
50+
page: 'https://feedbacker.com/pricing',
51+
createdAt: new Date('2020-12-23').getTime()
52+
},
53+
{
54+
text: 'Podia ter um botão de solicitar demo 2',
55+
fingerprint: '490135491',
56+
id: 'eab759f8-f238-4ff9-ae91-ee1558982329',
57+
apiKey: 'fcd5015c-10d3-4e9c-b395-ec7ed8850165',
58+
type: 'IDEA',
59+
device: 'Chrome 85.0, macOS 10.14',
60+
page: 'https://feedbacker.com/pricing',
61+
createdAt: new Date('2020-08-23').getTime()
62+
},
63+
{
64+
text: 'Muitos erros slkkkkkkk 2',
65+
fingerprint: '490135491',
66+
id: 'eab759f8-f238-4ff9-ae91-ee1558982329',
67+
apiKey: 'fcd5015c-10d3-4e9c-b395-ec7ed8850165',
68+
type: 'ISSUE',
69+
device: 'Chrome 85.0, macOS 10.14',
70+
page: 'https://feedbacker.com/pricing',
71+
createdAt: new Date('2020-05-23').getTime()
72+
}
73+
]
74+
}

backend/handlers/auth.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
const jwt = require('jsonwebtoken')
2+
3+
function CreateAuthHandler (db) {
4+
async function login (ctx) {
5+
const { email, password } = ctx.request.body
6+
const user = await db.readOneByEmail('users', email)
7+
8+
if (!user) {
9+
ctx.status = 404
10+
ctx.body = { error: 'Not found' }
11+
return
12+
}
13+
14+
const canLogin = () => (
15+
user.email === email &&
16+
user.password === password
17+
)
18+
19+
if (!canLogin()) {
20+
ctx.status = 401
21+
ctx.body = { error: 'Unauthorized' }
22+
return
23+
}
24+
25+
const token = jwt.sign({
26+
id: user.id,
27+
email: user.email,
28+
name: user.name
29+
}, process.env.JWT_SECRET)
30+
31+
ctx.status = 200
32+
ctx.body = { token }
33+
}
34+
35+
return { login }
36+
}
37+
38+
module.exports = CreateAuthHandler

backend/handlers/feedbacks.js

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
const { v4: uuidv4 } = require('uuid')
2+
3+
const FEEDBACK_TYPES = {
4+
ISSUE: 'ISSUE',
5+
IDEA: 'IDEA',
6+
OTHER: 'OTHER'
7+
}
8+
9+
function CreateFeedbackHandler (db) {
10+
async function create (ctx) {
11+
const {
12+
type,
13+
text,
14+
fingerprint,
15+
device,
16+
page
17+
} = ctx.request.body
18+
19+
if (!type) {
20+
ctx.status = 400
21+
ctx.body = { error: 'type is empty' }
22+
}
23+
if (!text) {
24+
ctx.status = 400
25+
ctx.body = { error: 'text is empty' }
26+
}
27+
if (!fingerprint) {
28+
ctx.status = 400
29+
ctx.body = { error: 'fingerprint is empty' }
30+
}
31+
if (!device) {
32+
ctx.status = 400
33+
ctx.body = { error: 'device is empty' }
34+
}
35+
if (!page) {
36+
ctx.status = 400
37+
ctx.body = { error: 'page is empty' }
38+
}
39+
40+
if (!FEEDBACK_TYPES[String(type).toUpperCase()]) {
41+
ctx.status = 422
42+
ctx.body = { error: 'Unknown feedback type' }
43+
return
44+
}
45+
46+
const feedback = {
47+
text,
48+
fingerprint,
49+
id: uuidv4(),
50+
type: String(type).toUpperCase(),
51+
device,
52+
page,
53+
createdAt: new Date().getTime()
54+
}
55+
56+
const inserted = await db.insert('feedback', feedback)
57+
if (inserted) {
58+
ctx.status = 201
59+
ctx.body = feedback
60+
return
61+
}
62+
63+
ctx.status = 422
64+
ctx.body = { error: 'Feedback not created' }
65+
}
66+
67+
async function getFeedbacks (ctx) {
68+
let {
69+
type,
70+
limit = 5,
71+
offset = 0
72+
} = ctx.query
73+
let feedbacks = await db.readAll('feedbacks')
74+
75+
feedbacks = feedbacks.filter((feedback) => {
76+
return feedback.apiKey === ctx.state.user.apiKey
77+
})
78+
79+
if (type) {
80+
feedbacks = feedbacks.filter((feedback) => {
81+
return feedback.type === type
82+
})
83+
}
84+
85+
if (limit > 10) {
86+
limit = 5
87+
}
88+
if (offset > limit) {
89+
offset = limit
90+
}
91+
92+
feedbacks = feedbacks.slice(offset, limit)
93+
94+
ctx.status = 200
95+
ctx.body = feedbacks || []
96+
}
97+
98+
async function getFeedbacksByFingerprint (ctx) {
99+
const { fingerprint } = ctx.request.query
100+
const feedbacks = await db.readAll('feedbacks')
101+
const feedbacksFiltered = feedbacks.map((feedback) => {
102+
return feedback.fingerprint === fingerprint
103+
})
104+
105+
ctx.status = 200
106+
ctx.body = feedbacksFiltered || []
107+
}
108+
109+
async function getFeedbackById (ctx) {
110+
const { id } = ctx.params
111+
const feedback = await db.readOneById('feedback', id)
112+
if (!feedback) {
113+
ctx.status = 404
114+
ctx.body = { error: 'Feedback not found' }
115+
return
116+
}
117+
ctx.status = 200
118+
ctx.body = feedback
119+
}
120+
121+
return {
122+
create,
123+
getFeedbacks,
124+
getFeedbacksByFingerprint,
125+
getFeedbackById
126+
}
127+
}
128+
129+
module.exports = CreateFeedbackHandler

0 commit comments

Comments
 (0)