Compare commits

...

23 Commits

Author SHA1 Message Date
Matjaz
c023856981 Cleanup ... 2022-03-02 21:39:56 +01:00
Matjaz
f2762a02f9 Cleanup ... 2022-03-02 21:39:36 +01:00
Matjaz
0305c721ba delo na profilih 2022-03-02 21:11:43 +01:00
Matjaz
78f5b7acec Dodani avatarji in stran z nastavitvami. 2022-03-01 23:40:45 +01:00
Matjaz
5435ba2d45 New field in Users table for avatar and bio. 2022-03-01 20:53:01 +01:00
Matjaz
bb72b9d1d5 Cleanup. 2022-03-01 20:39:49 +01:00
Matjaz
44b14487bf Lepše prikažemo sporočila - upoštevamo novo vrstico. 2022-02-27 23:21:36 +01:00
Matjaz
4f15826cba Odstrani db iz git-a. 2022-02-27 23:06:52 +01:00
Matjaz
c34df3560f Popravek gitignore. 2022-02-27 23:04:05 +01:00
Matjaz
d5ff307fba Timeline je polno funkcionalen. 2022-02-27 23:02:08 +01:00
Matjaz
34177d6b2d Delo na timeline. 2022-02-23 23:33:17 +01:00
ebdacff5bc Add database to gitignore. 2022-02-19 12:28:52 +01:00
Matjaz
a347e79ded Cleanup. 2022-02-13 21:50:44 +01:00
Matjaz
da1ef02782 Začetek časovnice. 2022-02-13 21:48:01 +01:00
fe774158ff UUID paket dodan. 2022-02-12 12:28:02 +01:00
Matjaz
438145dc08 Čiščenje messages route. 2022-02-11 21:39:04 +01:00
Matjaz
eb618954a3 Izdelano objavljanje sporočil. 2022-02-11 21:36:43 +01:00
Matjaz
3ad790ff89 Login sistem deluje. 2022-02-11 20:02:52 +01:00
Matjaz
40da8e140d Nadaljevanje. 2022-02-10 07:42:27 +01:00
Matjaz
a429c9262b Registracijski sistem. 2022-02-09 22:51:27 +01:00
Matjaz
0b40010581 Login izdelan ... približno. 2022-02-09 20:31:07 +01:00
Matjaz
0f739adfb2 Začetek obrazca za prijavo. 2022-02-09 19:32:45 +01:00
Matjaz
32f7c6caa1 Testiranje modelov. 2022-02-09 19:32:06 +01:00
31 changed files with 5694 additions and 168 deletions

1
.gitignore vendored
View File

@ -116,3 +116,4 @@ dist
.yarn/install-state.gz
.pnp.*
database/socialbot.db

13
app.js
View File

@ -2,16 +2,22 @@ var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var logger = require('morgan');
const fileUpload = require('express-fileupload');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/user');
var messagesRouter = require('./routes/message');
var loginRouter = require('./routes/login');
var registerRouter = require('./routes/register');
var followRouter = require('./routes/follow');
var app = express();
const db = require('./models');
db.sequelize.sync({ force: true });
// db.sequelize.sync({ force: true });
db.sequelize.sync();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
@ -21,11 +27,16 @@ app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(fileUpload());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/user', usersRouter);
app.use('/message', messagesRouter);
app.use('/login', loginRouter);
app.use('/register', registerRouter);
app.use('/follow', followRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {

Binary file not shown.

28
lib/index.js Normal file
View File

@ -0,0 +1,28 @@
var db = require('../models');
var User = db.User;
var Session = db.Session;
async function getAuthUser(sessionId) {
var session;
var user;
if(sessionId != undefined) {
session = await Session.findOne({
include: User,
where: {
sessionid: sessionId
}
});
if(session) {
user = session.User;
return user;
} else {
return;
}
} else {
return;
}
}
module.exports = {
getAuthUser,
};

View File

@ -0,0 +1,30 @@
'use strict';
module.exports = {
async up(queryInterface, Sequelize) {
await queryInterface.createTable('Sessions', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
sessionid: {
type: Sequelize.TEXT
},
agentid: {
type: Sequelize.TEXT
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
async down(queryInterface, Sequelize) {
await queryInterface.dropTable('Sessions');
}
};

View File

@ -0,0 +1,39 @@
'use strict';
module.exports = {
async up (queryInterface, Sequelize) {
/**
* Add altering commands here.
*
* Example:
* await queryInterface.createTable('users', { id: Sequelize.INTEGER });
*/
await queryInterface.addColumn(
'Users',
'avatar',
{
type: Sequelize.BLOB,
allowNull: true,
},
);
await queryInterface.addColumn(
'Users',
'bio',
{
type: Sequelize.TEXT,
allowNull: true,
}
);
},
async down (queryInterface, Sequelize) {
/**
* Add reverting commands here.
*
* Example:
* await queryInterface.dropTable('users');
*/
await queryInterface.removeColumn('Users', 'avatar');
await queryInterface.removeColumn('Users', 'bio');
}
};

View File

@ -24,8 +24,11 @@ fs
db[model.name] = model;
});
db.User.hasMany(db.Message, {foreignKey: 'UserId'});
db.Message.belongsTo(db.User);
db.User.belongsToMany(db.Message, {foreignKey: 'UserId', through: 'UserMessages'});
db.Message.belongsTo(db.User, {through: 'UserMessages'});
db.User.hasMany(db.Session);
db.Session.belongsTo(db.User);
db.User.belongsToMany(db.User, {as: 'follow', through: 'UserFollows'});
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {

24
models/session.js Normal file
View File

@ -0,0 +1,24 @@
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Session extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}
}
Session.init({
sessionid: DataTypes.TEXT,
agentid: DataTypes.TEXT
}, {
sequelize,
modelName: 'Session',
});
return Session;
};

View File

@ -16,7 +16,9 @@ module.exports = (sequelize, DataTypes) => {
User.init({
name: DataTypes.STRING,
password: DataTypes.STRING,
email: DataTypes.STRING
email: DataTypes.STRING,
avatar: DataTypes.BLOB,
bio: DataTypes.STRING
}, {
sequelize,
modelName: 'User',

4405
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,16 +6,22 @@
"start": "node ./bin/www"
},
"dependencies": {
"body-parser": "^1.19.1",
"connect-busboy": "^1.0.0",
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"ejs": "~2.6.1",
"express": "~4.16.1",
"express-busboy": "^8.0.0",
"express-fileupload": "^1.3.1",
"http-errors": "~1.6.3",
"morgan": "~1.9.1",
"sequelize": "^6.15.0",
"sqlite3": "^5.0.2"
"sqlite3": "^5.0.2",
"uuid": "^8.3.2"
},
"devDependencies": {
"jshint": "^2.13.4",
"postcss": "^8.4.6",
"sequelize-cli": "^6.4.1",
"tailwind-scrollbar": "^1.3.1",

View File

@ -1,5 +1,9 @@
/*
! tailwindcss v3.0.18 | MIT License | https://tailwindcss.com
/*
npx tailwindcss -i ./src/style.css -o ./public/stylesheets/style.css --watch
*/
/*
! tailwindcss v3.0.18 | MIT License | https://tailwindcss.com
*/
/*
@ -423,6 +427,11 @@ Ensure the default browser behavior of the `hidden` attribute.
display: none;
}
* {
scrollbar-color: initial;
scrollbar-width: initial;
}
*, ::before, ::after {
--tw-translate-x: 0;
--tw-translate-y: 0;
@ -502,21 +511,25 @@ Ensure the default browser behavior of the `hidden` attribute.
margin-right: auto;
}
.mx-2 {
margin-left: 0.5rem;
margin-right: 0.5rem;
}
.my-4 {
margin-top: 1rem;
margin-bottom: 1rem;
}
.mx-2 {
margin-left: 0.5rem;
margin-right: 0.5rem;
}
.my-5 {
margin-top: 1.25rem;
margin-bottom: 1.25rem;
}
.mt-2 {
margin-top: 0.5rem;
}
.mt-5 {
margin-top: 1.25rem;
}
@ -525,6 +538,14 @@ Ensure the default browser behavior of the `hidden` attribute.
margin-right: 0.5rem;
}
.mr-4 {
margin-right: 1rem;
}
.mb-4 {
margin-bottom: 1rem;
}
.mr-3 {
margin-right: 0.75rem;
}
@ -533,12 +554,8 @@ Ensure the default browser behavior of the `hidden` attribute.
margin-top: 0.75rem;
}
.mb-4 {
margin-bottom: 1rem;
}
.mr-4 {
margin-right: 1rem;
.mt-4 {
margin-top: 1rem;
}
.block {
@ -549,6 +566,10 @@ Ensure the default browser behavior of the `hidden` attribute.
display: flex;
}
.inline-flex {
display: inline-flex;
}
.hidden {
display: none;
}
@ -561,6 +582,14 @@ Ensure the default browser behavior of the `hidden` attribute.
height: 9rem;
}
.h-12 {
height: 3rem;
}
.h-24 {
height: 6rem;
}
.max-h-40 {
max-height: 10rem;
}
@ -569,6 +598,10 @@ Ensure the default browser behavior of the `hidden` attribute.
max-height: 2.5rem;
}
.min-h-screen {
min-height: 100vh;
}
.w-6 {
width: 1.5rem;
}
@ -577,6 +610,14 @@ Ensure the default browser behavior of the `hidden` attribute.
width: 100%;
}
.w-12 {
width: 3rem;
}
.w-24 {
width: 6rem;
}
.max-w-lg {
max-width: 32rem;
}
@ -601,6 +642,10 @@ Ensure the default browser behavior of the `hidden` attribute.
align-items: center;
}
.items-baseline {
align-items: baseline;
}
.justify-end {
justify-content: flex-end;
}
@ -640,6 +685,10 @@ Ensure the default browser behavior of the `hidden` attribute.
border-radius: 0.375rem;
}
.rounded-lg {
border-radius: 0.5rem;
}
.border {
border-width: 1px;
}
@ -658,6 +707,11 @@ Ensure the default browser behavior of the `hidden` attribute.
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
.bg-blue-500 {
--tw-bg-opacity: 1;
background-color: rgb(59 130 246 / var(--tw-bg-opacity));
}
.bg-gray-700 {
--tw-bg-opacity: 1;
background-color: rgb(55 65 81 / var(--tw-bg-opacity));
@ -678,6 +732,11 @@ Ensure the default browser behavior of the `hidden` attribute.
background-color: rgb(75 85 99 / var(--tw-bg-opacity));
}
.bg-gray-100 {
--tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
}
.object-none {
-o-object-fit: none;
object-fit: none;
@ -730,6 +789,21 @@ Ensure the default browser behavior of the `hidden` attribute.
padding-right: 1rem;
}
.px-8 {
padding-left: 2rem;
padding-right: 2rem;
}
.py-6 {
padding-top: 1.5rem;
padding-bottom: 1.5rem;
}
.px-6 {
padding-left: 1.5rem;
padding-right: 1.5rem;
}
.pl-2 {
padding-left: 0.5rem;
}
@ -746,6 +820,14 @@ Ensure the default browser behavior of the `hidden` attribute.
padding-right: 1.25rem;
}
.text-left {
text-align: left;
}
.text-center {
text-align: center;
}
.align-bottom {
vertical-align: bottom;
}
@ -760,6 +842,16 @@ Ensure the default browser behavior of the `hidden` attribute.
line-height: 1.75rem;
}
.text-2xl {
font-size: 1.5rem;
line-height: 2rem;
}
.text-xs {
font-size: 0.75rem;
line-height: 1rem;
}
.font-bold {
font-weight: 700;
}
@ -769,14 +861,24 @@ Ensure the default browser behavior of the `hidden` attribute.
color: rgb(75 85 99 / var(--tw-text-opacity));
}
.text-white {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.text-gray-400 {
--tw-text-opacity: 1;
color: rgb(156 163 175 / var(--tw-text-opacity));
}
.text-white {
.text-blue-600 {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
color: rgb(37 99 235 / var(--tw-text-opacity));
}
.text-gray-500 {
--tw-text-opacity: 1;
color: rgb(107 114 128 / var(--tw-text-opacity));
}
.shadow {
@ -791,6 +893,56 @@ Ensure the default browser behavior of the `hidden` attribute.
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.shadow-lg {
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.scrollbar.overflow-y-hidden {
overflow-y: hidden;
}
.scrollbar-thin {
--scrollbar-track: initial;
--scrollbar-thumb: initial;
scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
overflow: overlay;
}
.scrollbar-thin.overflow-x-hidden {
overflow-x: hidden;
}
.scrollbar-thin.overflow-y-hidden {
overflow-y: hidden;
}
.scrollbar-thin::-webkit-scrollbar-track {
background-color: var(--scrollbar-track);
}
.scrollbar-thin::-webkit-scrollbar-thumb {
background-color: var(--scrollbar-thumb);
}
.scrollbar-thin {
scrollbar-width: thin;
}
.scrollbar-thin::-webkit-scrollbar {
width: 8px;
height: 8px;
}
.scrollbar-track-gray-\37 00 {
--scrollbar-track: #374151 !important;
}
.scrollbar-thumb-gray-\39 00 {
--scrollbar-thumb: #111827 !important;
}
.focus-within\:text-gray-400:focus-within {
--tw-text-opacity: 1;
color: rgb(156 163 175 / var(--tw-text-opacity));
@ -801,6 +953,16 @@ Ensure the default browser behavior of the `hidden` attribute.
background-color: rgb(75 85 99 / var(--tw-bg-opacity));
}
.hover\:bg-blue-900:hover {
--tw-bg-opacity: 1;
background-color: rgb(30 58 138 / var(--tw-bg-opacity));
}
.hover\:underline:hover {
-webkit-text-decoration-line: underline;
text-decoration-line: underline;
}
.focus\:text-blue-400:focus {
--tw-text-opacity: 1;
color: rgb(96 165 250 / var(--tw-text-opacity));
@ -811,6 +973,17 @@ Ensure the default browser behavior of the `hidden` attribute.
outline-offset: 2px;
}
.focus\:ring-1:focus {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);
box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);
}
.focus\:ring-blue-600:focus {
--tw-ring-opacity: 1;
--tw-ring-color: rgb(37 99 235 / var(--tw-ring-opacity));
}
@media (prefers-color-scheme: dark) {
.dark\:bg-gray-800 {
--tw-bg-opacity: 1;
@ -849,6 +1022,11 @@ Ensure the default browser behavior of the `hidden` attribute.
}
@media (min-width: 1024px) {
.lg\:mx-10 {
margin-left: 2.5rem;
margin-right: 2.5rem;
}
.lg\:mx-3 {
margin-left: 0.75rem;
margin-right: 0.75rem;
@ -862,6 +1040,10 @@ Ensure the default browser behavior of the `hidden` attribute.
height: 100vh;
}
.lg\:w-1\/4 {
width: 25%;
}
.lg\:w-72 {
width: 18rem;
}
@ -878,4 +1060,12 @@ Ensure the default browser behavior of the `hidden` attribute.
padding-left: 6rem;
padding-right: 6rem;
}
.scrollbar.lg\:overflow-y-hidden {
overflow-y: hidden;
}
.scrollbar-thin.lg\:overflow-y-hidden {
overflow-y: hidden;
}
}

38
routes/follow.js Normal file
View File

@ -0,0 +1,38 @@
var express = require('express');
var router = express.Router();
var db = require('../models');
var User = db.User;
var Messages = db.Messages;
var Session = db.Session;
var lib = require('../lib');
/* GET home page. */
router.get('/add/:id', async function(req, res, next) {
var id = req.params.id;
console.log(req.cookies.sessionid);
var sessionId = req.cookies.sessionid;
var user = await lib.getAuthUser(sessionId);
if(user) {
var follow = await user.addFollow(id);
res.send(follow);
} else {
res.redirect('/login');
}
});
router.get('/get', async function(req, res, next) {
var id = req.params.id;
console.log(req.cookies.sessionid);
var sessionId = req.cookies.sessionid;
var user = await lib.getAuthUser(sessionId);
if(user) {
var follow = await user.getFollow({
attributes: ['id']
});
res.send(follow);
} else {
res.redirect('/login');
}
});
module.exports = router;

View File

@ -1,9 +1,64 @@
var express = require('express');
var router = express.Router();
var db = require('../models');
var User = db.User;
var Messages = db.Messages;
var Session = db.Session;
var lib = require('../lib');
var Op = db.Sequelize.Op;
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
router.get('/me', async function(req, res, next) {
console.log(req.cookies.sessionid);
var sessionId = req.cookies.sessionid;
var user = await lib.getAuthUser(sessionId);
if(user) {
var messages = await user.getMessages({
order: [
['id', 'DESC'],
],
limit: 10
});
var messageCount = await user.countMessages();
res.render('me', { auth:user, messages:messages, messageCount:messageCount });
} else {
res.redirect('/login');
}
});
router.get('/', async function(req, res, next) {
var sessionId = req.cookies.sessionid;
var user = await lib.getAuthUser(sessionId);
if(user) {
var follows = await user.getFollow({
attributes: {
include: [
'id',
]
}
});
var userList = [];
userList.push(user.id);
follows.forEach(element => {
userList.push(element.id);
});
var userMessages = await db.Message.findAll({
include: User,
where: {
'$User.id$': {
[Op.in]: userList
}
},
order: [
['updatedAt', 'DESC']
]
});
//console.log(await userMessages[0].getUsers());
res.render('index', {auth:user, messages:userMessages, messageCount:3});
} else {
res.redirect('/login');
}
});
module.exports = router;

43
routes/login.js Normal file
View File

@ -0,0 +1,43 @@
var express = require('express');
const { UniqueConstraintError } = require('sequelize/dist/index.js');
var router = express.Router();
const db = require('../models');
var User = db.User;
const uuidv4 = require('uuid').v4;
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('login', { title: 'Express' });
});
router.post('/', async function(req, res, next) {
console.log(req.body);
var user = await User.findOne({
where: {
email: req.body.email,
password: req.body.password
}
});
console.log(user);
if(user) {
var uuid = uuidv4();
var agentid = req.rawHeaders[3];
var session = await user.createSession({
sessionid: uuid,
agentid: agentid
});
console.log(session);
var maxage = 60 * 60 * 24 * 1000;
res.cookie('sessionid', session.sessionid, {maxAge: maxage, httpOnly: true});
res.redirect('/');
} else {
res.render('login');
}
});
router.get('/logout', function(req, res, next) {
res.clearCookie('sessionid');
res.redirect('/login');
});
module.exports = router;

View File

@ -1,17 +1,107 @@
var express = require('express');
const db = require('../models');
var router = express.Router();
var lib = require('../lib');
var Message = db.Message;
var User = db.User;
/* GET users listing. */
router.get('/', async function(req, res, next) {
var messages = await Message.findAll();
res.send(messages);
var Op = db.Sequelize.Op;
async function getAllMessages(user) {
if(user) {
var follows = await user.getFollow();
var timelineMessages = [];
for(var i = 0; i < follows.length; i++) {
timelineMessages[i] = follows[i]
timelineMessages[i].messages = [];
var messages = await follows[i].getMessages();
for(var j = 0; j < messages.length; j++) {
timelineMessages[i].messages.push(messages[j]);
}
}
//var messages = fore
return timelineMessages;
}
}
/* POST a new message */
router.post('/add', async function(req, res, next) {
var sessionId = req.cookies.sessionid;
var user = await lib.getAuthUser(sessionId);
if(user) {
var message = await user.createMessage({ body: req.body.body });
console.log(message);
message.setUser(user);
res.redirect('/');
} else {
res.redirect('/login');
}
});
router.get('/new', async function(req, res, next) {
var message = await Message.create({'body':'My First Message', UserId:3});
res.send(message);
router.get('/timeline', async function(req, res, next) {
var sessionId = req.cookies.sessionid;
var user = await lib.getAuthUser(sessionId);
var timeline = await getAllMessages(user);
res.send(timeline);
});
router.get('/timeline2', async function(req, res, next) {
var sessionId = req.cookies.sessionid;
var user = await lib.getAuthUser(sessionId);
if(user) {
var follows = await user.getFollow();
var userList = [];
follows.forEach(element => {
userList.push(element.id);
});
var userMessages = await db.User.findAll({
include: Message,
//required: true,
where: {
id: userList,
'$Messages.createdAt$': {
[Op.like]: '2022%',
}
},
});
res.send(userMessages);
} else {
res.redirect('/login');
}
});
router.get('/timeline3', async function(req, res, next) {
var sessionId = req.cookies.sessionid;
var user = await lib.getAuthUser(sessionId);
if(user) {
var follows = await user.getFollow({
attributes: {
include: [
'id',
]
}
});
var userList = [];
userList.push(user.id);
follows.forEach(element => {
userList.push(element.id);
});
var userMessages = await db.Message.findAll({
include: User,
where: {
'$User.id$': {
[Op.in]: userList
}
},
order: [
['updatedAt', 'DESC']
]
});
//console.log(await userMessages[0].getUsers());
res.send(userMessages);
} else {
res.redirect('/login');
}
});
module.exports = router;

27
routes/register.js Normal file
View File

@ -0,0 +1,27 @@
var express = require('express');
var router = express.Router();
const db = require('../models');
var User = db.User;
var Session = db.Session;
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('register');
});
router.post('/', async function(req, res, next) {
console.log(req.body);
if((req.body.username === '') || (req.body.email === '') || (req.body.password === '')) {
res.redirect('/register');
} else {
var user = await User.create({
name: req.body.username,
email: req.body.email,
password: req.body.password,
});
console.log(user);
res.redirect('/login');
}
});
module.exports = router;

View File

@ -2,30 +2,82 @@ var express = require('express');
const db = require('../models');
var router = express.Router();
var User = db.User;
var lib = require('../lib');
/* GET users listing. */
router.get('/', async function(req, res, next) {
var users = await User.findAll();
res.send(users);
router.get('/profile/:username', async function(req, res, next) {
var test = 123;
var sessionId = req.cookies.sessionid;
var search = req.params.username;
var auth = await lib.getAuthUser(sessionId);
if(auth) {
var user = await User.findOne({
where: {
name: search,
}
});
if(user) {
var messages = await user.getMessages();
var messageCount = await user.countMessages();
res.render('user', {auth:auth, user:user, messages:messages, messageCount:messageCount});
} else {
res.redirect('/');
}
} else {
res.redirect('/login');
}
});
router.get('/get/:id', async function(req, res, next) {
var users = await User.findByPk (req.params.id);
res.send(users);
router.get('/settings', async function(req, res, next) {
var sessionId = req.cookies.sessionid;
var auth = await lib.getAuthUser(sessionId);
if(auth) {
res.render('settings', { auth:auth });
} else {
res.redirect('/login');
}
});
router.put('/update/:id', async function(req, res, next) {
var users = await User.update({'email':'eve@uplink.si'}, {where:{'ID':req.params.id}});
res.send(users);
router.post('/settings', async function(req, res, next) {
var sessionId = req.cookies.sessionid;
var auth = await lib.getAuthUser(sessionId);
var newData = {};
if(req.body.bio != '') {
newData.bio = req.body.bio;
}
if(req.body.name != '') {
newData.name = req.body.name;
}
if(req.files) {
if(req.files.avatar.data) {
newData.avatar = req.files.avatar.data;
}
}
if(auth) {
console.log(req);
console.log(req.files);
await auth.update(newData);
res.redirect('/user/settings');
} else {
res.redirect('/login');
}
});
router.get('/new', async function(req, res, next) {
var users = await User.create({'name':'EVE2', 'email':'eve@2uplink.si', 'password':'some-random-password'});
res.send(users);
});
router.get('/add', function(req, res, next) {
res.send('respond with a resource');
router.get('/avatar/:id', async function(req, res, next) {
var user = await db.User.findOne({
where: {
id: req.params.id
}
});
res.contentType('image/png');
if(user.avatar) {
res.end(Buffer.from(user.avatar.buffer, 'base64'));
} else {
res.send();
}
//res.send(user.avatar.buffer);
});
module.exports = router;

View File

@ -0,0 +1,46 @@
'use strict';
module.exports = {
async up (queryInterface, Sequelize) {
/**
* Add seed commands here.
*
* Example:
* await queryInterface.bulkInsert('People', [{
* name: 'John Doe',
* isBetaMember: false
* }], {});
*/
await queryInterface.bulkInsert('users', [
{id: null, name: 'John Doe', email: 'John.Doe@email.com', password: 'password', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
{name: 'Valentin', password: 'random-password', email: 'valentin@uplink.si', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
{name: 'Helena', password: 'random-password', email: 'helena@uplink.si', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
{name: 'Oto', password: 'random-password', email: 'oto@uplink.si', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
{name: 'Peter', password: 'random-password', email: 'peter@uplink.si', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
{name: 'Igor', password: 'random-password', email: 'igor@uplink.si', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
{name: 'Matic', password: 'random-password', email: 'matic@uplink.si', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
{name: 'Jože', password: 'random-password', email: 'joze@uplink.si', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
{name: 'Marko', password: 'random-password', email: 'marko@uplink.si', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
{name: 'Marija', password: 'random-password', email: 'marija@uplink.si', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
{name: 'Brigita', password: 'random-password', email: 'brigita@uplink.si', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
{name: 'Andrej', password: 'random-password', email: 'andrej@uplink.si', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
{name: 'Jaka', password: 'random-password', email: 'jaka@uplink.si', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
{name: 'Natalija', password: 'random-password', email: 'natalija@uplink.si', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
{name: 'Lotta', password: 'random-password', email: 'lotta@uplink.si', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
{name: 'Sven', password: 'random-password', email: 'sven@uplink.si', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
{name: 'Bjorn', password: 'random-password', email: 'bjorn@uplink.si', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
{name: 'Lars', password: 'random-password', email: 'lars@uplink.si', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
{name: 'Matjaž', password: 'random-password', email: 'matjaz.m@uplink.si', createdAt: '2021-02-09 22:16:34.901 +00:00', updatedAt: '2022-02-09 22:16:34.901 +00:00'},
], {});
},
async down (queryInterface, Sequelize) {
/**
* Add commands to revert seed here.
*
* Example:
* await queryInterface.bulkDelete('People', null, {});
*/
//await queryInterface.bulkDelete('Users', null, {});
}
};

View File

@ -1,3 +1,7 @@
/*
npx tailwindcss -i ./src/style.css -o ./public/stylesheets/style.css --watch
*/
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@ -32,50 +32,26 @@
</form>
<div class="flex items-center justify-between mt-5">
<div class="flex items-center">
<img src="/images/avatar_48.png" alt="John Doe" class="rounded-md mr-2">
<img src="/user/avatar/<%- auth.id %>" alt="<%= auth.name %>" class="rounded-md mr-2">
<div>
<div class="w-full font-bold text-sm">John Doe</div>
<div class="w-full text-sm text-gray-400">john.doe@uplink.si</div>
<div class="w-full font-bold text-sm"><%= auth.name %></div>
<div class="w-full text-sm text-gray-400"><%= auth.email %></div>
</div>
</div>
<div>
<button type="button" data-dropdown-toggle="dropdown" id="profileDropdownButton" class="bg-gray-700 rounded-md mx-2 px-2 focus:text-blue-400 text-lg font-bold" aria-expanded="true" aria-haspopup="true"><i class="fa fa-angle-down"></i></button>
<!-- This is an example component -->
<div class="max-w-lg mx-auto">
<!-- Dropdown menu -->
<div class="hidden dark:bg-gray-700 dark:text-white z-50 list-none divide-y divide-gray-100 rounded-md shadow my-4" id="dropdown">
<ul class="py-1" aria-labelledby="dropdown">
<li>
<a href="#" class="text-sm hover:bg-gray-600 text-white block px-3 py-1">Dashboard</a>
</li>
<li>
<a href="#" class="text-sm hover:bg-gray-600 text-white block px-3 py-1">Settings</a>
</li>
<li>
<a href="#" class="text-sm hover:bg-gray-600 text-white block px-3 py-1">Earnings</a>
</li>
<li>
<a href="#" class="text-sm hover:bg-gray-600 text-white block px-3 py-1">Sign out</a>
</li>
</ul>
</div>
</div>
<script src="/scripts/flowbite.js"></script>
<%- include('partials/_user_dropdown.ejs') %>
</div>
</div>
<div class="my-5">
<form action="">
<form method="POST" action="/message/add">
<textarea
class="w-full h-36 p-1 dark:text-white dark:bg-gray-900 focus:outline-none dark:focus:bg-white dark:focus:text-gray-900 text-sm"
name="body" id="" cols="20" placeholder="What's on your mind?"></textarea>
name="body" id="body" cols="20" placeholder="What's on your mind?"></textarea>
<hr class="my-4">
<div class="flex justify-end">
<button
class="place-content-end bg-blue-600 py-2 px-5 rounded-md mr-3 focus:outline-none focus:shadow-outline"
type="submit">TOOT!</button>
class="place-content-end bg-blue-600 py-2 px-5 rounded-md mr-3 focus:outline-none focus:shadow-outline font-bold"
type="submit">Send</button>
</div>
</form>
</div>
@ -85,7 +61,7 @@
class="lg:flex-1 lg:mx-3 max-w-xl min-w-md dark:bg-gray-600 dark:text-white scrollbar-thin scrollbar-thumb-gray-900 scrollbar-track-gray-700 overflow-y-scroll">
<div class="lg:h-screen">
<div class="bg-gray-900 text-white p-4 flex justify-between w-full z-50"">
<div><i class=" fa fa-home mr-2"></i>Home</div>
<div><a href="/"><i class=" fa fa-home mr-2"></i>Home</a></div>
<div><i class="fa fa-sliders"></i></div>
</div>
<div class="max-h-40 overflow-y-hidden align-bottom">
@ -93,7 +69,7 @@
</div>
<div class="flex justify-between">
<div class="flex-shrink-0 max-h-10 relative -top-10 px-4">
<img src="/images/avatar_94.png" alt="John Doe" class="rounded-md overflow-visible">
<img src="/user/avatar/<%= auth.id %>" alt="<%= auth.name %>" class="rounded-md overflow-visible w-24 h-24">
</div>
<div class="flex items-center pt-3 px-2 mx-2">
<button class="bg-blue-600 py-2 px-5 rounded-md mr-3 focus:outline-none focus:shadow-outline"
@ -106,61 +82,24 @@
<div class="p-4">
<div>
<h4 class="font-bold">John Doe</h4>
<p class="text-sm text-gray-400">john.doe@uplink.si</p>
<h4 class="font-bold"><%= auth.name %></h4>
<p class="text-sm text-gray-400"><%= auth.email %></p>
</div>
<div class="text-sm text-gray-400 mt-3">
<p>Joined Dec 28, 2021</p>
<div class="my-4"><p><%= auth.bio %></p></div>
<p>Joined <%= auth.createdAt %></p>
<div class="flex">
<div class="pr-5"><span class="text-white">5</span> Posts</div>
<div class="pr-5"><span class="text-white"><%= messageCount %></span> Posts</div>
<div class="pr-5"><span class="text-white">3</span> Following</div>
<div class="pr-5"><span class="text-white">7</span> Followers</div>
</div>
</div>
</div>
<% for(var i=0; i < 8; i++) {%>
<%- include('partials/_toot') %>
<% } %>
<%- include('partials/_messages', {messages:messages}) %>
</div>
</div>
<div class="lg:w-72 lg:overflow-y-hidden">
<ul class="p-5">
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-home mr-2"></i>Home</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-bell mr-2"></i>Notifications</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-group mr-2"></i>Local</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-globe mr-2"></i>Federated</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-envelope mr-2"></i>Direct messages</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-star mr-2"></i>Favourites</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-bookmark mr-2"></i>Bookmarks</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-list mr-2"></i>Lists</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-address-book mr-2"></i>Profile directory</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-cog mr-2"></i>Preferences</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-group mr-2"></i>Follows and followers</a>
</li>
</ul>
</div>
<%- include('partials/_sidebar_menu.ejs') %>
</div>
</div>

37
views/login.ejs Normal file
View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html class="dark">
<head>
<title>Social Robot</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/stylesheets/style.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.2.0/css/fork-awesome.min.css"
integrity="sha256-XoaMnoYC5TH6/+ihMEnospgm0J1PM/nioxbOUdnM8HY=" crossorigin="anonymous">
</head>
<div class="flex items-center justify-center min-h-screen bg-gray-100">
<div class="px-8 py-6 mt-4 text-left bg-white shadow-lg">
<h3 class="text-2xl font-bold text-center">Login to your account</h3>
<form action="/login" method="POST">
<div class="mt-4">
<div>
<label class="block" for="email">Email<label>
<input name="email" type="text" placeholder="Email"
class="w-full px-4 py-2 mt-2 border rounded-md focus:outline-none focus:ring-1 focus:ring-blue-600">
</div>
<div class="mt-4">
<label class="block">Password<label>
<input name="password" type="password" placeholder="Password"
class="w-full px-4 py-2 mt-2 border rounded-md focus:outline-none focus:ring-1 focus:ring-blue-600">
</div>
<div class="flex items-baseline justify-between">
<button type="submit" class="px-6 py-2 mt-4 text-white bg-blue-600 rounded-lg hover:bg-blue-900">Login</button>
<a href="/register" class="text-sm text-blue-600 hover:underline">Register</a>
</div>
</div>
</form>
</div>
</div>
</html>

108
views/me.ejs Normal file
View File

@ -0,0 +1,108 @@
<!DOCTYPE html>
<html class="dark">
<head>
<title>Social Robot</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/stylesheets/style.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.2.0/css/fork-awesome.min.css"
integrity="sha256-XoaMnoYC5TH6/+ihMEnospgm0J1PM/nioxbOUdnM8HY=" crossorigin="anonymous">
</head>
<body class="bg-white dark:bg-gray-800 dark:text-white">
<div class="lg:px-24 mx-auto">
<div class="lg:flex justify-center">
<div class="lg:w-72 lg:overflow-y-hidden">
<form method="GET">
<div class="relative text-gray-600 focus-within:text-gray-400">
<span class="absolute inset-y-0 left-0 flex items-center pl-2">
<button type="submit" class="p-1 focus:outline-none focus:shadow-outline">
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
viewBox="0 0 24 24" class="w-6 h-6">
<path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
</svg>
</button>
</span>
<input type="search" name="q"
class="w-full py-2 text-sm dark:text-white dark:bg-gray-900 pl-10 focus:outline-none dark:focus:bg-white dark:focus:text-gray-900"
placeholder="Search..." autocomplete="off">
</div>
</form>
<div class="flex items-center justify-between mt-5">
<div class="flex items-center">
<img src="/user/avatar/<%- auth.id %>" alt="<%= auth.name %>" class="rounded-md mr-2">
<div>
<div class="w-full font-bold text-sm"><%= auth.name %></div>
<div class="w-full text-sm text-gray-400"><%= auth.email %></div>
</div>
</div>
<div>
<%- include('partials/_user_dropdown.ejs') %>
</div>
</div>
<div class="my-5">
<form method="POST" action="/message/add">
<textarea
class="w-full h-36 p-1 dark:text-white dark:bg-gray-900 focus:outline-none dark:focus:bg-white dark:focus:text-gray-900 text-sm"
name="body" id="body" cols="20" placeholder="What's on your mind?"></textarea>
<hr class="my-4">
<div class="flex justify-end">
<button
class="place-content-end bg-blue-600 py-2 px-5 rounded-md mr-3 focus:outline-none focus:shadow-outline font-bold"
type="submit">Send</button>
</div>
</form>
</div>
</div>
<div
class="lg:flex-1 lg:mx-3 max-w-xl min-w-md dark:bg-gray-600 dark:text-white scrollbar-thin scrollbar-thumb-gray-900 scrollbar-track-gray-700 overflow-y-scroll">
<div class="lg:h-screen">
<div class="bg-gray-900 text-white p-4 flex justify-between w-full z-50"">
<div><a href="/"><i class=" fa fa-home mr-2"></i>Home</a></div>
<div><i class="fa fa-sliders"></i></div>
</div>
<div class="max-h-40 overflow-y-hidden align-bottom">
<img class="object-none object-center" src="/images/19187755.jpg" alt="paralax">
</div>
<div class="flex justify-between">
<div class="flex-shrink-0 max-h-10 relative -top-10 px-4">
<img src="/user/avatar/<%= auth.id %>" alt="<%= auth.name %>" class="rounded-md overflow-visible w-24 h-24">
</div>
<div class="flex items-center pt-3 px-2 mx-2">
<button class="bg-blue-600 py-2 px-5 rounded-md mr-3 focus:outline-none focus:shadow-outline"
type="submit">Follow</button>
<button
class="bg-gray-600 border border-b-gray-400 py-2 px-5 rounded-md focus:outline-none focus:shadow-outline shadow-xl"
type="submit"><i class="fa fa-ellipsis-v"></i></button>
</div>
</div>
<div class="p-4">
<div>
<h4 class="font-bold"><%= auth.name %></h4>
<p class="text-sm text-gray-400"><%= auth.email %></p>
</div>
<div class="text-sm text-gray-400 mt-3">
<div class="my-4"><p><%= auth.bio %></p></div>
<p>Joined <%= auth.createdAt %></p>
<div class="flex">
<div class="pr-5"><span class="text-white"><%= messageCount %></span> Posts</div>
<div class="pr-5"><span class="text-white">3</span> Following</div>
<div class="pr-5"><span class="text-white">7</span> Followers</div>
</div>
</div>
</div>
<%- include('partials/_toot', {auth:auth, messages:messages}) %>
</div>
</div>
<%- include('partials/_sidebar_menu.ejs') %>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,25 @@
<!-- _messages.ejs -->
<% for(var i = 0; i < messages.length; i++) {%>
<div class="dark:bg-gray-700 flex p-4 border-b border-b-gray-400">
<div class="mr-4 flex-shrink-0">
<img src="/user/avatar/<%- messages[i].User.id %>" alt="<%= auth.name %>" class="rounded-md w-12 h-12">
</div>
<div>
<div>
<h5 class="font-bold mb-4">
<a href="/user/profile/<%= messages[i].User.name %>"><%= messages[i].User.name %></a>
</h5>
<p>
<% messages[i].body.split('\n').forEach(line => { %>
<%= line %><br>
<% }) %>
</p>
</div>
<div class="text-xs text-gray-500 mt-3">Posted on: <%= messages[i].createdAt %>
</div>
</div>
</div>
<% } %>

View File

@ -0,0 +1,38 @@
<!-- _sidebar_menu.ejs -->
<div class="lg:w-72 lg:overflow-y-hidden">
<ul class="p-5">
<li>
<a href="/" class="font-bold text-lg mb-4 block"><i class="fa fa-home mr-2"></i>Home</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-bell mr-2"></i>Notifications</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-group mr-2"></i>Local</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-globe mr-2"></i>Federated</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-envelope mr-2"></i>Direct messages</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-star mr-2"></i>Favourites</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-bookmark mr-2"></i>Bookmarks</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-list mr-2"></i>Lists</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-address-book mr-2"></i>Profile directory</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-cog mr-2"></i>Preferences</a>
</li>
<li>
<a class="font-bold text-lg mb-4 block"><i class="fa fa-group mr-2"></i>Follows and followers</a>
</li>
</ul>
</div>

View File

@ -1,18 +1,25 @@
<div class="dark:bg-gray-700 flex p-4 border-b border-b-gray-400">
<!-- _toot.ejs -->
<% for(var i = 0; i < messages.length; i++) {%>
<div class="dark:bg-gray-700 flex p-4 border-b border-b-gray-400">
<div class="mr-4 flex-shrink-0">
<img src="/images/avatar_48.png" alt="John Doe" class="rounded-md">
<img src="/user/avatar/<%- auth.id %>" alt="<%= auth.name %>" class="rounded-md w-12 h-12">
</div>
<div>
<h5 class="font-bold mb-4">John Doe</h5>
<div>
<h5 class="font-bold mb-4">
<a href="/user/profile/<%= auth.name %>"><%= auth.name %></a>
</h5>
<p>There are so many programs configurable in #Lua. I am making a list.</p>
<p>I revisited the tiling window manager topic. #awesomewm is configurable in Lua, but for now I think I will rewrite my #bspwm config in Lua and learn how to do more advanced customization with conditionals.</p>
<p>Found out that #conky's visualizations are done in Lua with the Cairo graphics library. That looks really cool and I hope to do some with that soon. </p>
<p>Set terminal text and bspwm to #gruvbox colors.</p>
<p>#RetroEdgeTechStack</p>
<p>
<% messages[i].body.split('\n').forEach(line => { %>
<%= line %><br>
<% }) %>
</p>
</div>
<div class="text-xs text-gray-500 mt-3">Posted on: <%= messages[i].createdAt %>
</div>
</div>
</div>
</div>
<% } %>

View File

@ -0,0 +1,27 @@
<!-- _user_dropdown.ejs -->
<button type="button" data-dropdown-toggle="dropdown" id="profileDropdownButton"
class="bg-gray-700 rounded-md mx-2 px-2 focus:text-blue-400 text-lg font-bold" aria-expanded="true"
aria-haspopup="true"><i class="fa fa-angle-down"></i></button>
<!-- This is an example component -->
<div class="max-w-lg mx-auto">
<!-- Dropdown menu -->
<div class="hidden dark:bg-gray-700 dark:text-white z-50 list-none divide-y divide-gray-100 rounded-md shadow my-4"
id="dropdown">
<ul class="py-1" aria-labelledby="dropdown">
<li>
<a href="/me" class="text-sm hover:bg-gray-600 text-white block px-3 py-1">Profile</a>
</li>
<li>
<a href="/user/settings" class="text-sm hover:bg-gray-600 text-white block px-3 py-1">Settings</a>
</li>
<li>
<a href="#" class="text-sm hover:bg-gray-600 text-white block px-3 py-1">Earnings</a>
</li>
<li>
<a href="/login/logout" class="text-sm hover:bg-gray-600 text-white block px-3 py-1">Sign out</a>
</li>
</ul>
</div>
</div>
<script src="/scripts/flowbite.js"></script>

View File

@ -0,0 +1,25 @@
<!-- _user_timeline.ejs -->
<% for(var i = 0; i < messages.length; i++) {%>
<div class="dark:bg-gray-700 flex p-4 border-b border-b-gray-400">
<div class="mr-4 flex-shrink-0">
<img src="/user/avatar/<%- user.id %>" alt="<%= user.name %>" class="rounded-md w-12 h-12">
</div>
<div>
<div>
<h5 class="font-bold mb-4">
<a href="/user/profile/<%= user.name %>"><%= user.name %></a>
</h5>
<p>
<% messages[i].body.split('\n').forEach(line => { %>
<%= line %><br>
<% }) %>
</p>
</div>
<div class="text-xs text-gray-500 mt-3">Posted on: <%= messages[i].createdAt %>
</div>
</div>
</div>
<% } %>

42
views/register.ejs Normal file
View File

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html class="dark">
<head>
<title>Social Robot</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/stylesheets/style.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.2.0/css/fork-awesome.min.css"
integrity="sha256-XoaMnoYC5TH6/+ihMEnospgm0J1PM/nioxbOUdnM8HY=" crossorigin="anonymous">
</head>
<div class="flex items-center justify-center min-h-screen bg-gray-100">
<div class="px-8 py-6 mt-4 text-left bg-white shadow-lg">
<h3 class="text-2xl font-bold text-center">Register new account</h3>
<form action="/register" method="POST">
<div class="mt-4">
<div>
<label class="block" for="username">Name<label>
<input name="username" type="text" placeholder="Name"
class="w-full px-4 py-2 mt-2 border rounded-md focus:outline-none focus:ring-1 focus:ring-blue-600">
</div>
<div class="mt-4">
<label class="block" for="email">Email<label>
<input name="email" type="text" placeholder="Email"
class="w-full px-4 py-2 mt-2 border rounded-md focus:outline-none focus:ring-1 focus:ring-blue-600">
</div>
<div class="mt-4">
<label class="block">Password<label>
<input name="password" type="password" placeholder="Password"
class="w-full px-4 py-2 mt-2 border rounded-md focus:outline-none focus:ring-1 focus:ring-blue-600">
</div>
<div class="flex items-baseline justify-between">
<button type="submit" class="px-6 py-2 mt-4 text-white bg-blue-600 rounded-lg hover:bg-blue-900">Register</button>
<a href="/login" class="text-sm text-blue-600 hover:underline">Already have account?</a>
</div>
</div>
</form>
</div>
</div>
</html>

130
views/settings.ejs Normal file
View File

@ -0,0 +1,130 @@
<!DOCTYPE html>
<html class="dark">
<head>
<title>Social Robot</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/stylesheets/style.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.2.0/css/fork-awesome.min.css"
integrity="sha256-XoaMnoYC5TH6/+ihMEnospgm0J1PM/nioxbOUdnM8HY=" crossorigin="anonymous">
</head>
<body class="bg-white dark:bg-gray-800 dark:text-white">
<div class="lg:px-24 mx-auto">
<div class="lg:flex justify-center">
<div class="lg:w-72 lg:overflow-y-hidden">
<form method="GET">
<div class="relative text-gray-600 focus-within:text-gray-400">
<span class="absolute inset-y-0 left-0 flex items-center pl-2">
<button type="submit" class="p-1 focus:outline-none focus:shadow-outline">
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
viewBox="0 0 24 24" class="w-6 h-6">
<path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
</svg>
</button>
</span>
<input type="search" name="q"
class="w-full py-2 text-sm dark:text-white dark:bg-gray-900 pl-10 focus:outline-none dark:focus:bg-white dark:focus:text-gray-900"
placeholder="Search..." autocomplete="off">
</div>
</form>
<div class="flex items-center justify-between mt-5">
<div class="flex items-center">
<img src="/user/avatar/<%- auth.id %>" alt="<%= auth.name %>" class="rounded-md mr-2">
<div>
<div class="w-full font-bold text-sm"><%= auth.name %></div>
<div class="w-full text-sm text-gray-400"><%= auth.email %></div>
</div>
</div>
<div>
<%- include('partials/_user_dropdown.ejs') %>
</div>
</div>
<div class="my-5">
<form method="POST" action="/message/add">
<textarea
class="w-full h-36 p-1 dark:text-white dark:bg-gray-900 focus:outline-none dark:focus:bg-white dark:focus:text-gray-900 text-sm"
name="body" id="body" cols="20" placeholder="What's on your mind?"></textarea>
<hr class="my-4">
<div class="flex justify-end">
<button
class="place-content-end bg-blue-600 py-2 px-5 rounded-md mr-3 focus:outline-none focus:shadow-outline font-bold"
type="submit">Send</button>
</div>
</form>
</div>
</div>
<div
class="lg:flex-1 lg:mx-3 max-w-xl min-w-md dark:bg-gray-600 dark:text-white scrollbar-thin scrollbar-thumb-gray-900 scrollbar-track-gray-700 overflow-y-scroll">
<div class="lg:h-screen">
<div class="bg-gray-900 text-white p-4 flex justify-between w-full z-50"">
<div><a href="/"><i class=" fa fa-home mr-2"></i>Home</a></div>
<div><i class="fa fa-sliders"></i></div>
</div>
<div class="max-h-40 overflow-y-hidden align-bottom">
<img class="object-none object-center" src="/images/19187755.jpg" alt="paralax">
</div>
<div class="flex justify-between">
<div class="flex-shrink-0 max-h-10 relative -top-10 px-4">
<img src="/user/avatar/<%= auth.id %>" alt="<%= auth.name %>" class="rounded-md overflow-visible w-24 h-24">
</div>
<div class="flex items-center pt-3 px-2 mx-2">
<button class="bg-blue-600 py-2 px-5 rounded-md mr-3 focus:outline-none focus:shadow-outline"
type="submit">Follow</button>
<button
class="bg-gray-600 border border-b-gray-400 py-2 px-5 rounded-md focus:outline-none focus:shadow-outline shadow-xl"
type="submit"><i class="fa fa-ellipsis-v"></i></button>
</div>
</div>
<div class="p-4">
<div>
<h4 class="font-bold"><%= auth.name %></h4>
<p class="text-sm text-gray-400"><%= auth.email %></p>
</div>
<div class="text-sm text-gray-400 mt-3">
<div class="my-4"><p><%= auth.bio %></p></div>
<p>Joined <%= auth.createdAt %></p>
<div class="flex">
<div class="pr-5"><span class="text-white">12</span> Posts</div>
<div class="pr-5"><span class="text-white">3</span> Following</div>
<div class="pr-5"><span class="text-white">7</span> Followers</div>
</div>
</div>
</div>
<!-- dodaj -->
<div class="p-4">
<form action="/user/settings" method="POST" enctype="multipart/form-data">
<div class="my-4 w-full">
<label for="name">Name:</label>
<input value="<%= auth.name %>" class="dark:text-white dark:bg-gray-900 focus:outline-none dark:focus:bg-white dark:focus:text-gray-900 text-sm" type="text" name="name" id="name">
</div>
<div class="my-4">
<input type="file" name="avatar" id="avatar" >
</div>
<div class="my-4">
<textarea
class="w-full h-36 p-1 dark:text-white dark:bg-gray-900 focus:outline-none dark:focus:bg-white dark:focus:text-gray-900 text-sm"
name="bio" id="body" cols="20" placeholder="A little bit about me"><%= auth.bio%></textarea>
</div>
<div class="my-4">
<button
class="place-content-end bg-blue-600 py-2 px-5 rounded-md mr-3 focus:outline-none focus:shadow-outline font-bold"
type="submit">Save</button>
</div>
</form>
</div>
</div>
</div>
<%- include('partials/_sidebar_menu.ejs') %>
</div>
</div>
</body>
</html>

118
views/user.ejs Normal file
View File

@ -0,0 +1,118 @@
<!DOCTYPE html>
<html class="dark">
<head>
<title>Social Robot</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/stylesheets/style.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.2.0/css/fork-awesome.min.css"
integrity="sha256-XoaMnoYC5TH6/+ihMEnospgm0J1PM/nioxbOUdnM8HY=" crossorigin="anonymous">
</head>
<body class="bg-white dark:bg-gray-800 dark:text-white">
<div class="lg:px-24 mx-auto">
<div class="lg:flex justify-center">
<div class="lg:w-72 lg:overflow-y-hidden">
<form method="GET">
<div class="relative text-gray-600 focus-within:text-gray-400">
<span class="absolute inset-y-0 left-0 flex items-center pl-2">
<button type="submit" class="p-1 focus:outline-none focus:shadow-outline">
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
viewBox="0 0 24 24" class="w-6 h-6">
<path d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
</svg>
</button>
</span>
<input type="search" name="q"
class="w-full py-2 text-sm dark:text-white dark:bg-gray-900 pl-10 focus:outline-none dark:focus:bg-white dark:focus:text-gray-900"
placeholder="Search..." autocomplete="off">
</div>
</form>
<div class="flex items-center justify-between mt-5">
<div class="flex items-center">
<img src="/user/avatar/<%- auth.id %>" alt="<%= auth.name %>" class="rounded-md mr-2">
<div>
<div class="w-full font-bold text-sm"><%= auth.name %></div>
<div class="w-full text-sm text-gray-400"><%= auth.email %></div>
</div>
</div>
<div>
<%- include('partials/_user_dropdown.ejs') %>
</div>
</div>
<div class="my-5">
<form method="POST" action="/message/add">
<textarea
class="w-full h-36 p-1 dark:text-white dark:bg-gray-900 focus:outline-none dark:focus:bg-white dark:focus:text-gray-900 text-sm"
name="body" id="body" cols="20" placeholder="What's on your mind?"></textarea>
<hr class="my-4">
<div class="flex justify-end">
<button
class="place-content-end bg-blue-600 py-2 px-5 rounded-md mr-3 focus:outline-none focus:shadow-outline font-bold"
type="submit">Send</button>
</div>
</form>
</div>
</div>
<div
class="lg:flex-1 lg:mx-3 max-w-xl min-w-md dark:bg-gray-600 dark:text-white scrollbar-thin scrollbar-thumb-gray-900 scrollbar-track-gray-700 overflow-y-scroll">
<div class="lg:h-screen">
<div class="bg-gray-900 text-white p-4 flex justify-between w-full z-50"">
<div><a href="/"><i class=" fa fa-home mr-2"></i>Home</a></div>
<div><i class="fa fa-sliders"></i></div>
</div>
<div class="max-h-40 overflow-y-hidden align-bottom">
<img class="object-none object-center" src="/images/19187755.jpg" alt="paralax">
</div>
<div class="flex justify-between">
<div class="flex-shrink-0 max-h-10 relative -top-10 px-4">
<img src="/user/avatar/<%= user.id %>" alt="<%= user.name %>" class="rounded-md overflow-visible w-24 h-24">
</div>
<div class="flex items-center pt-3 px-2 mx-2">
<a class="bg-blue-600
py-2
px-5
rounded-md
mr-3
focus:outline-none
focus:shadow-outline
inline-flex
items-center
"
href="/follow/add/<%= user.id %>">Follow</a>
<button
class="bg-gray-600 border border-b-gray-400 py-2 px-5 rounded-md focus:outline-none focus:shadow-outline shadow-xl"
type="submit"><i class="fa fa-ellipsis-v"></i></button>
</div>
</div>
<div class="p-4">
<div>
<h4 class="font-bold"><%= user.name %></h4>
<p class="text-sm text-gray-400"><%= user.email %></p>
</div>
<div class="text-sm text-gray-400 mt-3">
<div class="my-4"><p><%= user.bio %></p></div>
<p>Joined <%= user.createdAt %></p>
<div class="flex">
<div class="pr-5"><span class="text-white"><%= messageCount %></span> Posts</div>
<div class="pr-5"><span class="text-white">3</span> Following</div>
<div class="pr-5"><span class="text-white">7</span> Followers</div>
</div>
</div>
</div>
<%- include('partials/_user_timeline', {user:user, messages:messages}) %>
</div>
</div>
<%- include('partials/_sidebar_menu.ejs') %>
</div>
</div>
</body>
</html>