diff --git a/config/passport.js b/config/passport.js index 5c2339ef..f3dd7468 100644 --- a/config/passport.js +++ b/config/passport.js @@ -1,4 +1,4 @@ -/** UNFINISHED **/ +/* UNFINISHED */ /* eslint-disable no-unused-vars */ const passport = require('passport'); diff --git a/controllers/backend/account.js b/controllers/backend/account.js index 05166bb5..2f8029e2 100644 --- a/controllers/backend/account.js +++ b/controllers/backend/account.js @@ -1,6 +1,7 @@ -/** UNFINISHED **/ +/* UNFINISHED */ /* eslint-disable no-unused-vars */ +const express = require("express"); // JSDoc types only const bluebird = require('bluebird'); const Promise = require('bluebird'); const crypto = bluebird.promisifyAll(require('crypto')); @@ -15,6 +16,7 @@ const mv = require('mv'); const fs = require('fs-extra'); const mkdirp = Promise.promisifyAll(require('mkdirp')); const randomstring = require('randomstring'); + const mailJet = require('../../lib/emails/mailjet'); const sendgrid = require('../../lib/emails/sendgrid'); @@ -49,8 +51,8 @@ const recaptcha = new reCAPTCHA({ secretKey : process.env.RECAPTCHA_SECRETKEY }); -const { b2 } = require('../../lib/uploading/backblaze'); -const pagination = require('../../lib/helpers/pagination'); +// const { b2 } = require('../../lib/uploading/backblaze'); +// const pagination = require('../../lib/helpers/pagination'); // where to send users to after login const redirectUrl = '/account'; @@ -110,28 +112,41 @@ exports.postLogin = async(req, res, next) => { }; /** - * POST /signup + * `POST` `/signup` + * * Create a new local account. + * + * TODO: write tests for it. + * @param {express.Request} req + * @param {express.Response} res + * @param {express.NextFunction} next */ -exports.postSignup = async(req, res, next) => { +exports.postSignup = async (req, res, next) => { // CAPTCHA VALIDATION - if(process.env.NODE_ENV == 'production' && process.env.RECAPTCHA_ON == 'true'){ + if (process.env.NODE_ENV == 'production' && process.env.RECAPTCHA_ON == 'true') { + try { const response = await recaptcha.validate(req.body['g-recaptcha-response']); } catch(err){ req.flash('errors', { msg: 'Captcha failed, please try again' }); return res.redirect('/signup'); } + } - /** assertion testing the data **/ + /* assertion testing the data */ // req.assert('email', 'Email is not valid').isEmail(); - req.assert('password', 'Password must be at least 4 characters long').len(4); + req.assert('password', 'Password must be at least 4 characters long').len({min: 4}); req.assert('confirmPassword', 'Passwords do not match').equals(req.body.password); // req.assert('channelName', 'Channel name must be entered').notEmpty(); - req.assert('channelUrl', 'Channel username must be entered').notEmpty(); - req.assert('channelUrl', 'Channel username must be between 3 and 25 characters.').len(3,25); + req.assert('channelUrl', 'Channel username must be entered') + .notEmpty() + .len({ min: 3, max: 25 }).withMessage("Channel username must be between 3 and 25 characters.") + + /* Data sanitization */ + req.sanitize("channelUrl").trim(); + req.sanitize("channelUrl").escape(); console.log(req.body.channelUrl + ' <--- inputted channelUrl for' + req.body.email); // console.log(req.body.grecaptcha.getResponse('captcha')); @@ -158,9 +173,9 @@ exports.postSignup = async(req, res, next) => { }); // make sure first user is admin, can refactor later - const numberOfUsers = await User.countDocuments(); + const randomUser = await User.findOne(); - if(numberOfUsers == 0){ + if(!randomUser){ user.role = 'admin'; user.plan = 'plus'; user.privs.unlistedUpload = true; @@ -200,13 +215,17 @@ exports.postSignup = async(req, res, next) => { }; /** - * POST /account/profile + * `POST` `/account/profile` + * * Update profile information. + * + * @param {express.Request} req + * @param {express.Response} res + * @param {express.NextFunction} next */ - exports.postUpdateProfile = async(req, res, next) => { - if(!req.user && req.body.uploadToken){ + if (!req.user && req.body.uploadToken) { req.user = await User.findOne({ uploadToken : req.body.uploadToken }); } @@ -215,7 +234,16 @@ exports.postUpdateProfile = async(req, res, next) => { console.log(`UPDATING PROFILE FOR ${req.user && req.user.channelUrl}`); + /* Data validation */ + req.assert("channelName", "Channel name must be between 3 to 25 characters long").len({ min: 3, max: 25 }); + req.assert("description", "Description can be 500 characters long at best").len({ max: 500 }); + + /* Data sanitization */ req.sanitize('email').normalizeEmail({ gmail_remove_dots: false }); + req.sanitize("channelName").trim(); + req.sanitize("channelName").escape(); + req.sanitize("description").trim(); + req.sanitize("description").escape(); const errors = req.validationErrors(); @@ -253,6 +281,7 @@ exports.postUpdateProfile = async(req, res, next) => { const channelUrlFolder = `${saveAndServeFilesDirectory}/${req.user.channelUrl}`; // make the directory if it doesnt exist + // @ts-expect-error await mkdirp.mkdirpAsync(channelUrlFolder); // save the file @@ -267,7 +296,9 @@ exports.postUpdateProfile = async(req, res, next) => { req.user.customThumbnail = `user-thumbnail${fileExtension}`; // if no channel name is given, save it as the channel url - req.user.channelName = req.body.channelName ? req.body.channelName : req.user.channelUrl; + req.user.channelName = req.body.channelName + ? req.body.channelName + : req.user.channelUrl; req.user.channelDescription = req.body.description; @@ -380,8 +411,12 @@ exports.postReset = async(req, res, next) => { }; /** - * POST /forgot + * `POST` `/forgot` + * * Create a random token, then the send user an email with a reset link. + * @param {express.Request} req + * @param {express.Response} res + * @param {express.NextFunction} next */ exports.postForgot = async(req, res, next) => { @@ -444,8 +479,12 @@ exports.postForgot = async(req, res, next) => { }; /** - * POST /account/email + * `POST` `/account/email` + * * Create a random token, then the send user an email with a confirmation link + * @param {express.Request} req + * @param {express.Response} res + * @param {express.NextFunction} next */ exports.postConfirmEmail = async(req, res, next) => { @@ -541,4 +580,4 @@ exports.postImporter = async(req, res) => { uniqueTag, channelUrl }); -}; +}; \ No newline at end of file diff --git a/controllers/backend/internalApi.js b/controllers/backend/internalApi.js index 33c32383..54611566 100644 --- a/controllers/backend/internalApi.js +++ b/controllers/backend/internalApi.js @@ -1,6 +1,7 @@ -/** UNFINISHED **/ +/* UNFINISHED */ /* eslint-disable no-unused-vars */ +const express = require("express"); // JSDoc types only const bluebird = require('bluebird'); const Promise = require('bluebird'); const request = bluebird.promisifyAll(require('request'), { multiArgs: true }); @@ -51,18 +52,20 @@ const frontendServer = process.env.FRONTEND_SERVER || ''; const createNotification = require('../../lib/helpers/notifications'); // models -const Upload = require('../../models/index').Upload; -const User = require('../../models/index').User; -const Comment = require('../../models/index').Comment; -const React = require('../../models/index').React; -const Subscription = require('../../models/index').Subscription; -const Notification = require('../../models/index').Notification; -const CreditAction = require('../../models/index').CreditAction; -const Report = require('../../models/index').Report; -const LastWatchedTime = require('../../models/index').LastWatchedTime; -const PushEndpoint = require('../../models/index').PushEndpoint; -const PushSubscription = require('../../models/index').PushSubscription; -const EmailSubscription = require('../../models/index').EmailSubscription; +const { + Upload, + User, + Comment, + React, + Subscription, + Notification, + CreditAction, + Report, + LastWatchedTime, + PushEndpoint, + PushSubscription, + EmailSubscription, +} = require('../../models/index'); const getMediaType = require('../../lib/uploading/media'); const pushNotificationLibrary = require('../../lib/mediaPlayer/pushNotification'); @@ -95,7 +98,7 @@ if(process.env.NODE_ENV !== 'production' && !process.env.UPLOAD_SERVER){ async function updateUsersUnreadSubscriptions(user){ const subscriptions = await Subscription.find({ subscribedToUser: user._id, active: true }); - for(const subscription of subscriptions){ + for (const subscription of subscriptions) { let subscribingUser = await User.findOne({ _id: subscription.subscribingUser }); subscribingUser.unseenSubscriptionUploads = subscribingUser.unseenSubscriptionUploads + 1; @@ -779,8 +782,11 @@ exports.deleteComment = async(req, res) => { }; /** - * POST /api/comment + * `POST` `/api/comment` + * * List of API examples. + * @param {express.Request} req + * @param {express.Response} res */ exports.postComment = async(req, res) => { @@ -793,6 +799,19 @@ exports.postComment = async(req, res) => { return res.send('failed to post comment'); } + /* Data validation */ + req.assert("comment", "The comment shoould have between 2 to 250 characters").len({ min: 2, max: 250 }); + + /* Data sanitization */ + req.sanitize("comment").trim(); + req.sanitize("comment").escape(); + + const errors = req.validationErrors(); + + if(errors){ + return res.status(422).json(errors); + } + try { // note: this functionality is kind of crappy so turning it off @@ -891,14 +910,12 @@ exports.postComment = async(req, res) => { res.json(responseObject); // res.send('success') - } - catch(err){ + } catch(err) { console.log(err); res.status(500); res.send('failed to post comment'); - } }; diff --git a/controllers/frontend/account.js b/controllers/frontend/account.js index 7200c505..f1fe8d75 100644 --- a/controllers/frontend/account.js +++ b/controllers/frontend/account.js @@ -1,49 +1,42 @@ -/** UNFINISHED **/ +/* UNFINISHED */ /* eslint-disable no-unused-vars */ +const express = require("express"); //JSDoc types only const randomstring = require('randomstring'); const _ = require('lodash'); -const User = require('../../models/index').User; -const Upload = require('../../models/index').Upload; -const Comment = require('../../models/index').Comment; -const View = require('../../models/index').View; -const SiteVisit = require('../../models/index').SiteVisit; -const React = require('../../models/index').React; -const Notification = require('../../models/index').Notification; -const SocialPost = require('../../models/index').SocialPost; -const Subscription = require('../../models/index').Subscription; -const PushSubscription = require('../../models/index').PushSubscription; -const EmailSubscription = require('../../models/index').EmailSubscription; - -const PushEndpoint = require('../../models/index').PushEndpoint; - const RSS = require('rss'); +const { URLSearchParams } = require('url'); +const validator = require('email-validator'); +const { + User, + Upload, + Comment, + View, + SiteVisit, + React, + Notification, + SocialPost, + Subscription, + PushSubscription, + EmailSubscription, + PushEndpoint +} = require('../../models/index'); const { uploadServer, uploadUrl } = require('../../lib/helpers/settings'); const { saveMetaToResLocalForChannelPage } = require('../../lib/mediaPlayer/generateMetatags'); const { filterUploadsByMediaType } = require('../../lib/mediaBrowsing/helpers'); const timeHelper = require('../../lib/helpers/time'); -const { URLSearchParams } = require('url'); -const brandName = process.env.INSTANCE_BRAND_NAME; - -const thumbnailServer = process.env.THUMBNAIL_SERVER || ''; const pagination = require('../../lib/helpers/pagination'); - const categories = require('../../config/categories'); - const uploadFilters = require('../../lib/mediaBrowsing/helpers'); - const { saveAndServeFilesDirectory } = require('../../lib/helpers/settings'); - const { userCanUploadContentOfThisRating } = require('../../lib/uploading/helpers'); - -const validator = require('email-validator'); - const { getUploadDuration } = require('../../lib/mediaBrowsing/helpers'); +const { attachDataToUploadsAsUploads } = require('../../lib/helpers/addFieldsToUploads'); const javascriptTimeAgo = require('javascript-time-ago'); javascriptTimeAgo.locale(require('javascript-time-ago/locales/en')); @@ -53,10 +46,10 @@ const timeAgoEnglish = new javascriptTimeAgo('en-US'); const secondsToFormattedTime = timeHelper.secondsToFormattedTime; +const brandName = process.env.INSTANCE_BRAND_NAME; +const thumbnailServer = process.env.THUMBNAIL_SERVER || ''; const forgotEmailFunctionalityOn = process.env.FORGOT_PASSWORD_EMAIL_FUNCTIONALITY_ON == 'true'; -const { attachDataToUploadsAsUploads } = require('../../lib/helpers/addFieldsToUploads'); - // TODO: pull this function out function removeTrailingSlash(requestPath){ if(requestPath.charAt(requestPath.length - 1) == '/'){ @@ -733,10 +726,13 @@ exports.getChannel = async(req, res) => { }; /** - * GET /notifications - * User's specific notifications page + * `GET` `/notifications` + * + * User's specific notifications page. + * @param {express.Request} req + * @param {express.Response} res */ -exports.notification = async(req, res) => { +exports.notification = async (req, res) => { let page = req.params.page; if(!page){ page = 1; } @@ -875,13 +871,14 @@ exports.logout = (req, res) => { }; /** - * GET /signup + * `GET` `/signup` + * * Signup page. + * @param {express.Request} req + * @param {express.Response} res */ exports.getSignup = (req, res) => { - const recaptchaPublicKey = process.env.RECAPTCHA_SITEKEY; - const captchaOn = process.env.RECAPTCHA_ON == 'true'; if(req.user){ @@ -895,8 +892,11 @@ exports.getSignup = (req, res) => { }; /** - * GET /account + * `GET` `/account` + * * Account page. + * @param {express.Request} req + * @param {express.Response} res */ exports.getAccount = async(req, res) => { const stripeToken = process.env.STRIPE_FRONTEND_TOKEN; @@ -928,8 +928,11 @@ exports.getAccount = async(req, res) => { }; /** - * GET /account/reactHistory + * `GET` `/account/reactHistory` + * * React history page. + * @param {express.Request} req + * @param {express.Response} res */ exports.getReactHistory = async(req, res) => { const reacts = await React.find({ @@ -1049,8 +1052,12 @@ exports.getForgot = (req, res) => { }; /** - * GET /account/unlink/:provider + * `GET` `/account/unlink/:provider` + * * Unlink OAuth provider. + * @param {express.Request} req + * @param {express.Response} res + * @param {express.NextFunction} next */ exports.getOauthUnlink = (req, res, next) => { const provider = req.params.provider; @@ -1137,8 +1144,11 @@ exports.livestreaming = async(req, res) => }; /** - * GET /importer + * `GET` `/importer` + * * Importer page. + * @param {express.Request} req + * @param {express.Response} res */ exports.getImporter = (req, res) => { diff --git a/controllers/frontend/mediaPlayer.js b/controllers/frontend/mediaPlayer.js index 0570f696..8108262e 100644 --- a/controllers/frontend/mediaPlayer.js +++ b/controllers/frontend/mediaPlayer.js @@ -69,8 +69,9 @@ function getFormattedFileSize(upload){ } /** - * GET /$user/$uploadUniqueTag - * Media player page + * `GET` `/$user/$uploadUniqueTag` + * + * Media player page. */ exports.getMedia = async(req, res) => { diff --git a/lib/mediaPlayer/generateCommentsObjects.js b/lib/mediaPlayer/generateCommentsObjects.js index b936b668..bac13841 100644 --- a/lib/mediaPlayer/generateCommentsObjects.js +++ b/lib/mediaPlayer/generateCommentsObjects.js @@ -1,8 +1,11 @@ -const _ = require('lodash'); - -const Comment = require('../../models/index.js').Comment; +// const _ = require('lodash'); +const { Comment } = require('../../models/index.js'); +/** + * @param {string} uploadId + * TODO: unescape text bodies + */ async function generateComments(uploadId){ /** COMMENTS **/ @@ -11,7 +14,10 @@ async function generateComments(uploadId){ upload: uploadId, visibility: 'public', inResponseTo : {$exists: false} - }).populate({path: 'responses commenter', populate: {path: 'commenter'}}); + }).populate({ + path: 'responses commenter', + populate: {path: 'commenter'} + }); let commentCount = 0; for(const comment of comments){ diff --git a/package-lock.json b/package-lock.json index e6cf1b97..b6fa2216 100644 --- a/package-lock.json +++ b/package-lock.json @@ -185,9 +185,9 @@ } }, "@types/bluebird": { - "version": "3.5.29", - "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.29.tgz", - "integrity": "sha512-kmVtnxTuUuhCET669irqQmPAez4KFnFVKvpleVRyfC3g+SHD1hIkFZcWLim9BVcwUBLO59o8VZE4yGCmTif8Yw==" + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.33.tgz", + "integrity": "sha512-ndEo1xvnYeHxm7I/5sF6tBvnsA4Tdi3zj1keRKRs12SP+2ye2A27NDJ1B6PqkfMbGAcT+mqQVqbZRIrhfOp5PQ==" }, "@types/body-parser": { "version": "1.17.1", @@ -2250,7 +2250,7 @@ "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha1-xPp8lUBKF6nD6Mp+FTcxK3NjMKw=" + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" }, "deep-is": { "version": "0.1.3", @@ -6123,7 +6123,7 @@ "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8=" + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" }, "lru-cache": { "version": "4.1.5", @@ -8688,7 +8688,7 @@ "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha1-zZJL9SAKB1uDwYjNa54hG3/A0+0=", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "requires": { "deep-extend": "^0.6.0", "ini": "~1.3.0", diff --git a/package.json b/package.json index f926a73c..99f3af0d 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "postinstall": "node ./copySettingsAndPrivateFiles.js", "eslint": "eslint ./", "eslint:fix": "./node_modules/.bin/eslint --fix .", - "dev": "nodemon -e pug,js app.js", + "dev": "nodemon -e js app.js", "memory": "node --max-old-space-size=4096 app.js", "cache": "node --max-old-space-size=8000 caching/runCaching.js", "caching": "node --max-old-space-size=8000 caching/runCaching.js", @@ -59,7 +59,7 @@ "express-session": "^1.16.1", "express-status-monitor": "^1.3.3", "express-useragent": "^1.0.12", - "express-validator": "^3.1.2", + "express-validator": "^3.2.1", "fbgraph": "^1.4.4", "file-type": "^15.0.1", "fluent-ffmpeg": "^2.1.2", diff --git a/routes.js b/routes.js index 4daf4c04..d7dd3c6c 100644 --- a/routes.js +++ b/routes.js @@ -29,7 +29,7 @@ const domainNameAndTLD = process.env.DOMAIN_NAME_AND_TLD; console.log(`DOMAIN NAME AND TLD: ${domainNameAndTLD}\n`); -/** passport config **/ +/* passport config */ const passportConfig = require('./config/passport'); const authMiddleware = require('./middlewares/shared/authentication'); @@ -309,7 +309,7 @@ function frontendRoutes(app){ // ?? app.get('/account/unlink/:provider', passportConfig.isAuthenticated, accountFrontendController.getOauthUnlink); - /** ACCOUNT APIS **/ + /* ACCOUNT APIS */ app.post('/account/password', passportConfig.isAuthenticated, accountBackendController.postUpdatePassword); app.post('/account/delete', passportConfig.isAuthenticated, accountBackendController.postDeleteAccount); app.post('/account/profile', passportConfig.isAuthenticated, accountBackendController.postUpdateProfile); diff --git a/views/account/account.pug b/views/account/account.pug index 7b0ec56b..10417e1a 100644 --- a/views/account/account.pug +++ b/views/account/account.pug @@ -72,44 +72,43 @@ block content cursor: pointer; } - //form(action='https://www.paypal.com/cgi-bin/webscr', method='post') - // // Identify your business so that you can collect the payments. - // input(type='hidden', name='business', value='ceo@pew.tube') - // // Specify a Subscribe button. - // input(type='hidden', name='cmd', value='_xclick-subscriptions') - // // Identify the subscription. - // input(type='hidden', name='item_name', value="Recurring PewTube Account Top-Up") - // //input(type='hidden', name='item_number', value='Purchase Acount Top-Up') - // // Set the terms of the regular subscription. - // input(type='hidden', name='a3', value='5.00') - // input(type='hidden', name='p3', value='1') - // input(type='hidden', name='t3', value='M') - // // Set recurring payments until canceled. - // input(type='hidden', name='src', value='1') - // // Provide a drop-down menu option field. - // input(type='hidden', name='on0', value='Format') - // | Format - // br - // select(name='os0') - // option(value='Select a format') -- Select a format -- - // option(value='plaintext') Plain text - // option(value='HTML') HTML - // br - // // Display the payment button. - // input(type='image', name='submit', src='https://www.paypalobjects.com/webstatic/en_US/i/btn/png/btn_subscribe_113x26.png', alt='Subscribe') - // img(alt='', width='1', height='1', src='https://www.paypalobjects.com/en_US/i/scr/pixel.gif') + //- form(action='https://www.paypal.com/cgi-bin/webscr', method='post') + //- // Identify your business so that you can collect the payments. + //- input(type='hidden', name='business', value='ceo@pew.tube') + //- // Specify a Subscribe button. + //- input(type='hidden', name='cmd', value='_xclick-subscriptions') + //- // Identify the subscription. + //- input(type='hidden', name='item_name', value="Recurring PewTube Account Top-Up") + //- //input(type='hidden', name='item_number', value='Purchase Acount Top-Up') + //- // Set the terms of the regular subscription. + //- input(type='hidden', name='a3', value='5.00') + //- input(type='hidden', name='p3', value='1') + //- input(type='hidden', name='t3', value='M') + //- // Set recurring payments until canceled. + //- input(type='hidden', name='src', value='1') + //- // Provide a drop-down menu option field. + //- input(type='hidden', name='on0', value='Format') + //- | Format + //- br + //- select(name='os0') + //- option(value='Select a format') -- Select a format -- + //- option(value='plaintext') Plain text + //- option(value='HTML') HTML + //- br + //- // Display the payment button. + //- input(type='image', name='submit', src='https://www.paypalobjects.com/webstatic/en_US/i/btn/png/btn_subscribe_113x26.png', alt='Subscribe') + //- img(alt='', width='1', height='1', src='https://www.paypalobjects.com/en_US/i/scr/pixel.gif') .container include ./accountHeader - h1.fw.text-center Channel Overview hr - // TODO: export a variable plus_enabled if user enables payments - // TODO: has to have styled updated with fw + //- TODO: export a variable plus_enabled if user enables payments + //- TODO: has to have styled updated with fw if process.env.PLUS_ENABLED == 'true' h2.fw.text-center(style="margin-bottom:16px") Upgrade To #{brandName} Plus @@ -118,18 +117,19 @@ block content p Thank you so much for subscribing! p Your support makes NewTube possible p Please enjoy your new features: - //h4 Automatic YouTube backup functionality, unlisted uploads, private uploads, 2GB upload size - // h4 Livestreaming, unlisted uploads, private uploads, 2GB upload size + //-h4 Automatic YouTube backup functionality, unlisted uploads, private uploads, 2GB upload size + //- h4 Livestreaming, unlisted uploads, private uploads, 2GB upload size h4 Unlisted uploads, private uploads, 2GB upload size else - // - Unlisted, private and scheduled uploads + //- + - Unlisted, private and scheduled uploads - Built in monetization via direct payments (COMING SOON) - One-click complete YouTube backup (including future uploads) - Access to NodeTube Recording Studio (COMING EVENTUALLY) - //- NewTube Recording Studio (Coming Soon) + //- NewTube Recording Studio (Coming Soon) p.fw(style="white-space:pre-line;margin-bottom:19px;font-size:19px;margin-top:23px;"). @@ -145,37 +145,31 @@ block content - Support alternative tech that values your speech and privacy - // - Secure purchase through Stripe - - + //- - Secure purchase through Stripe //- One-click complete YouTube backup (including future uploads) - - button.stripe-button-el#customButton(type="submit" class="stripe-button-el" style="visibility: visible;") span(style="display: block; min-height: 30px;") Buy Now - // img(src="/images/stripe-white.png" style="max-width:200px") - - //br - //br - // - //button.stripe-button-el#customButton(type="submit" class="stripe-button-el" style="visibility: visible;") - // span(style="display: block; min-height: 30px;") Buy Month Subscription + //- img(src="/images/stripe-white.png" style="max-width:200px") - //br - //br - // - //button.stripe-button-el#customButton(type="submit" class="stripe-button-el" style="visibility: visible;") - // span(style="display: block; min-height: 30px;") Buy Year Subscription + //- br + //- br + + //- button.stripe-button-el#customButton(type="submit" class="stripe-button-el" style="visibility: visible;") + //- span(style="display: block; min-height: 30px;") Buy Month Subscription + //- br + //- br + + //- button.stripe-button-el#customButton(type="submit" class="stripe-button-el" style="visibility: visible;") + //- span(style="display: block; min-height: 30px;") Buy Year Subscription br br br - - // if you're allowed to - if user.plan == 'plus' && user.privs.youtubeBackup + //- if you're allowed to + if user.plan == 'plus' && user.privs.youtubeBackup h3.ytBackup br br @@ -183,15 +177,15 @@ block content h3.fw.text-center(style="") YouTube Backup br - //form - // .form-group - // .col-sm-offset-3.col-sm-7 - // a.btn.btn-block.btn-google.btn-social(href='/auth/youtube') - // i.fa.fa-youtube - // | Sign in with YouTube - // - //br - //br + //-form + //- .form-group + //- .col-sm-offset-3.col-sm-7 + //- a.btn.btn-block.btn-google.btn-social(href='/auth/youtube') + //- i.fa.fa-youtube + //- | Sign in with YouTube + //- + //-br + //-br if !user.youtubeChannelId form.form-horizontal @@ -205,7 +199,6 @@ block content i.fa.fa-pencil | Save Channel Username - br div.form-group.disabled label.col-sm-3.control-label(for='youtubeChannelId') Status @@ -229,16 +222,16 @@ block content br h2.fw.text-center Channel Information - br - br + br + br - //form.upload-form(role="form" method="POST" enctype="multipart/form-data") + //- form.upload-form(role="form" method="POST" enctype="multipart/form-data") form.update-user-details-form.form-horizontal(role="form" method="POST" enctype="multipart/form-data" action=`${thumbnailServer}/account/profile`) input(type="hidden" name="uploadToken" value=`${user.uploadToken}`) .form-group label.fw.col-sm-3.control-label(for='channelName' style="font-size:17px;margin-top:16px;") Channel Username .col-sm-7 - h3.fw= user.channelUrl + h3.fw #{user.channelUrl} .form-group label.fw.col-sm-3.control-label(for='channelName' style="font-size:17px;margin-top:-5px;") Channel Display Name @@ -250,20 +243,20 @@ block content .col-sm-7 textarea(id="description" name="description" maxlength='500' rows="7" cols="70" style="max-width:100%;color:#262525;") #{user.channelDescription} - // UPLOAD FORM IF NO THUMBNAIL + //- UPLOAD FORM IF NO THUMBNAIL if !user.thumbnailUrl .form-group label.fw.col-sm-3.control-label(for='channelName' style="font-size:17px;margin-top:-5px;") Channel Thumbnail .col-sm-7 - // FILE INPUT BUTTON + //- FILE INPUT BUTTON input.center-block.text-center.fw(class="upload-file" data-max-size="500000000" type="file" name="filetoupload" accept="image/*" style="margin:0;margin-bottom:3px;border:0px;") - //div.form-group - // div.col-sm-3. - // p.col-sm-7(style="white-space:pre-line;margin-top:-15px;margin-bottom:-1px;"). - // Thumbnail dimensions: - // width: up to 302px, - // height: 168px + //-div.form-group + //- div.col-sm-3. + //- p.col-sm-7(style="white-space:pre-line;margin-top:-15px;margin-bottom:-1px;"). + //- Thumbnail dimensions: + //- width: up to 302px, + //- height: 168px .form-group .col-sm-offset-3.col-sm-4 @@ -272,7 +265,7 @@ block content | Update Profile - // DISPLAY THUMBNAIL IF IT EXISTS + //- DISPLAY THUMBNAIL IF IT EXISTS if user.thumbnailUrl || user.customThumbnail br @@ -281,7 +274,7 @@ block content h2.fw.text-center Channel Thumbnail br - // TODO: Sub out thumbnail here + //- TODO: Sub out thumbnail here if user.customThumbnail a(href=`${uploadServer}/${user.channelUrl}/${user.customThumbnail}`) @@ -300,7 +293,7 @@ block content i.fa.fa-pencil | Delete - // EMAIL FUNCTIONALITY + //- EMAIL FUNCTIONALITY if verifyEmailFunctionalityOn @@ -313,14 +306,14 @@ block content h5.fw(style='font-size:19px;margin-top:18px;') Email Address : #{user.email} - // TODO: Have to finish this, can't think of a good design since I don't want users to spam emails - // TODO: also, the frontend is largely in place just needs a swal "Your email was deleted" + //- TODO: Have to finish this, can't think of a good design since I don't want users to spam emails + //- TODO: also, the frontend is largely in place just needs a swal "Your email was deleted" button.fw.btn.btn.btn-danger.btn-sm.center-block.text-center.deleteEmailButton(type='submit' style="margin-top:20px;border-radius:3px;") i.fa.fa-pencil | Delete br - // IS USER HAS PENDING CONFIRMATION EMAIL + //- IS USER HAS PENDING CONFIRMATION EMAIL if user.email && !user.emailConfirmed h3.fw.text-center Save Email br @@ -336,7 +329,7 @@ block content i.fa.fa-envelope | Resend Confirmation Email - // IF USER HAS NOT SAVED EMAIL + //- IF USER HAS NOT SAVED EMAIL if !user.email h3.fw.text-center Save Email br diff --git a/views/account/accountHeader.pug b/views/account/accountHeader.pug index b3cf886d..9ba9f97b 100644 --- a/views/account/accountHeader.pug +++ b/views/account/accountHeader.pug @@ -1,35 +1,35 @@ div.row - div.col-sm-2 - h3.fw - a(href=`/user/${user.channelUrl}`) Channel Page - - if user && user.privs && user.privs.livestreaming - div.col-sm-2 - h3.fw - a(href="/account/livestreaming") Livestreaming + div.col-sm-2 + h3.fw + a(href=`/user/${user.channelUrl}`) Channel Page + if user && user.privs && user.privs.livestreaming div.col-sm-2 - h3.fw - a(href=`/account/extra`) Extra - //div.col-sm-2 - // h3.fw - // a(href="/account/viewHistory") View History - //div.col-sm-2 - // h3.fw - // a(href="/account/reactHistory") React History - //div.col-sm-2 - // h3.fw - // a(href="/" + `${user.channelUrl}` + "/playlists") Playlists + h3.fw + a(href="/account/livestreaming") Livestreaming + + //- div.col-sm-2 + //- h3.fw + //- a(href=`/account/extra`) Extra + //- //- + //- div.col-sm-2 + //- h3.fw + //- a(href="/account/viewHistory") View History + //- div.col-sm-2 + //- h3.fw + //- a(href="/account/reactHistory") React History + //- div.col-sm-2 + //- h3.fw + //- a(href="/" + `${user.channelUrl}` + "/playlists") Playlists - //a.livestream-button Livestreaming - //a.livestreaming-link(href=`/user/${user.channelUrl}/live/staging`) Livestreaming - //div.col-sm-2 - // h3.fw Credit ($#{user.credit/100}) - //div.col-sm-2 - // h3.fw Earnings ($#{user.receivedCredit / 100}) - //div.col-sm-2 - // h3 - // a(href=`/account/creditHistory`) Credit History + //- //-a.livestream-button Livestreaming + //- //-a.livestreaming-link(href=`/user/${user.channelUrl}/live/staging`) Livestreaming + //-div.col-sm-2 + //- h3.fw Credit ($#{user.credit/100}) + //-div.col-sm-2 + //- h3.fw Earnings ($#{user.receivedCredit / 100}) + //-div.col-sm-2 + //- h3 + //- a(href=`/account/creditHistory`) Credit History -p hr diff --git a/views/account/signup.pug b/views/account/signup.pug index 4d61b0ed..ead32f87 100644 --- a/views/account/signup.pug +++ b/views/account/signup.pug @@ -1,55 +1,49 @@ extends ../layout - - block content style. - .firstPasswordInput, .confirmPasswordInput { + .firstPasswordInput, + .confirmPasswordInput { width: 88% } - .container - .page-header - h3.fw.center-block.text-center(style="font-size:33px;") Sign Up + h1.page-header.fw.center-block.text-center(style="font-size:33px;") Sign Up + + section.container form.form-horizontal.signup-form(id='signup-form', method='POST') input(type='hidden', name='_csrf', value=_csrf) - //.form-group - // label.col-sm-3.control-label(for='channelName') Display Name - // .col-sm-7 - // input.form-control(type='text', name='channelName', id='channelName', placeholder='The name that shows up for your channel', - // autofocus, minlength=3, maxlength=25, required) + //-.form-group + //- label.col-sm-3.control-label(for='channelName') Display Name + //- .col-sm-7 + //- input.form-control(type='text', name='channelName', id='channelName', placeholder='The name that shows up for your channel', + //- autofocus, minlength=3, maxlength=25, required) .form-group - label.fw.loginHeader.col-sm-3.control-label(for='channelUrl') Channel Username + label.fw.loginHeader.col-sm-3.control-label(for='channelUrl') Channel Username: .col-sm-7 input.fw.loginHeader.form-control.username(type='text', name='channelUrl', id='channelUrl', autofocus, required placeholder='Please choose your channel username') .form-group - label.fw.loginHeader.col-sm-3.control-label(for='password') Password + label.fw.loginHeader.col-sm-3.control-label(for='password') Password: .col-sm-7 input.fw.loginHeader.form-control.firstPasswordInput(type='password', name='password', id='password', placeholder='Please enter your password', required) .form-group - label.fw.loginHeader.col-sm-3.control-label(for='confirmPassword') Confirm Password + label.fw.loginHeader.col-sm-3.control-label(for='confirmPassword') Confirm Password: .col-sm-7 input.fw.loginHeader.form-control.confirmPasswordInput(type='password', name='confirmPassword', id='confirmPassword', placeholder='Please confirm your password', required) if captchaOn == true .form-group label.fw.loginHeader.col-sm-3.control-label(for='captcha') Captcha - //.col-sm-offset-3.col-sm-7 + //- .col-sm-offset-3.col-sm-7 .form-group.col-md-4(style="margin-left:1pt;") .g-recaptcha(data-sitekey=`${recaptchaPublicKey}` id='captcha') - //var regex = new RegExp("^[a-zA-Z]+$"); - + //- - var regex = new RegExp("^[a-zA-Z]+$"); .form-group .col-sm-offset-3.col-sm-7 - p.fw By signing up you are agreeing you have read and agree to the - a(href="/termsofservice")  Terms Of Service + p.fw By signing up you are agreeing you have read and agree to the #[a(href="/termsofservice") Terms Of Service]. .form-group .col-sm-offset-3.col-sm-7 - button.fw.loginHeader.btn.btn-success(type='submit' style="border-radius:8px;width:133px;") - i.fa.fa-user-plus - | Signup - + button.fw.loginHeader.btn.btn-success(type='submit' style="border-radius:8px;width:133px;") #[span.fa.fa-user-plus] Signup script. $('.signup-form').submit(function (evt) { diff --git a/views/media.pug b/views/media.pug index 5fa9bf3a..fa9d1f1d 100644 --- a/views/media.pug +++ b/views/media.pug @@ -16,8 +16,8 @@ block content } } - // TODO: make this cover more qualities - // TODO: also consider using upload.video + //- TODO: make this cover more qualities + //- TODO: also consider using upload.video if upload.bitrateInKbps > 1500 && upload.fileType == 'video' style. /** everything 650 and below */ @@ -718,14 +718,14 @@ block content - //if maxRatingAllowed !== 'SFW' - // if upload.rating - // if upload.rating == 'allAges' - // p.fw(style="margin-top:15px;font-size:12px;") Rating: Safe For Work - // if upload.rating == 'mature' - // p.fw(style="margin-top:15px;font-size:12px;") Rating: Not Safe For Work - // if upload.rating == 'sensitive' - // p.fw(style="margin-top:15px;font-size:12px;") Rating: Sensitive (18+) + //-if maxRatingAllowed !== 'SFW' + //- if upload.rating + //- if upload.rating == 'allAges' + //- p.fw(style="margin-top:15px;font-size:12px;") Rating: Safe For Work + //- if upload.rating == 'mature' + //- p.fw(style="margin-top:15px;font-size:12px;") Rating: Not Safe For Work + //- if upload.rating == 'sensitive' + //- p.fw(style="margin-top:15px;font-size:12px;") Rating: Sensitive (18+) if convertedRating !== 'SFW' @@ -759,14 +759,14 @@ block content div.col-sm-12(style="margin-top:50px") if user if !viewingUserIsBlocked - // comment form + //- comment form div.comment-form.form-group form.form-horizontal.overall-comment-form(class="comment-form" action='/api/comment', method='post') input(type='hidden', name='_csrf', value=_csrf) label.fw(for="comment" style="font-size:20px;") Enter Comment br input(type="hidden" name="upload" id="upload" value=upload._id) - textarea.commentInput.fw(name="comment" id="comment" minlength="2" style="width:800px;height:129px;max-width:100%;background-color:#151515;color:white;") + textarea.commentInput.fw(name="comment" id="comment" minlength="2" maxlength="250" style="width:800px;height:129px;max-width:100%;background-color:#151515;color:white;") br input.fw.btn.btn-md.btn-success.postCommentButton(type='submit' value="Post Comment" style="border-radius:4px") else @@ -1417,7 +1417,7 @@ block extra_footer_js - //COMMENT FUNCTIONALITY CONTAINED HERE + //- COMMENT FUNCTIONALITY CONTAINED HERE script(src="/js/media.js")