Compare commits
No commits in common. "single_docker" and "dev/prod" have entirely different histories.
single_doc
...
dev/prod
18 changed files with 67 additions and 238 deletions
110
Dockerfile
110
Dockerfile
|
@ -1,106 +1,6 @@
|
||||||
FROM node:12.16.1 as base
|
FROM node:12.16.1 as base
|
||||||
ENV APP_HOME=/usr/src/app \
|
ENV APP_HOME=/usr/src/app \
|
||||||
TERM=xterm
|
TERM=xterm
|
||||||
|
|
||||||
# Merge in mongodb to have a single image for Plesk deploy
|
|
||||||
# Code from: https://github.com/docker-library/mongo/blob/c9d4281a620f1e1ee95aaa084c5b60fc68ba65b9/3.6/Dockerfile
|
|
||||||
# add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added
|
|
||||||
RUN groupadd -r mongodb && useradd -r -g mongodb mongodb
|
|
||||||
|
|
||||||
RUN set -eux; \
|
|
||||||
apt-get update; \
|
|
||||||
apt-get install -y --no-install-recommends \
|
|
||||||
ca-certificates \
|
|
||||||
jq \
|
|
||||||
numactl \
|
|
||||||
; \
|
|
||||||
if ! command -v ps > /dev/null; then \
|
|
||||||
apt-get install -y --no-install-recommends procps; \
|
|
||||||
fi; \
|
|
||||||
rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# grab gosu for easy step-down from root (https://github.com/tianon/gosu/releases)
|
|
||||||
ENV GOSU_VERSION 1.12
|
|
||||||
# grab "js-yaml" for parsing mongod's YAML config files (https://github.com/nodeca/js-yaml/releases)
|
|
||||||
ENV JSYAML_VERSION 3.13.1
|
|
||||||
|
|
||||||
RUN set -ex; \
|
|
||||||
\
|
|
||||||
savedAptMark="$(apt-mark showmanual)"; \
|
|
||||||
apt-get update; \
|
|
||||||
apt-get install -y --no-install-recommends \
|
|
||||||
wget \
|
|
||||||
; \
|
|
||||||
if ! command -v gpg > /dev/null; then \
|
|
||||||
apt-get install -y --no-install-recommends gnupg dirmngr; \
|
|
||||||
savedAptMark="$savedAptMark gnupg dirmngr"; \
|
|
||||||
elif gpg --version | grep -q '^gpg (GnuPG) 1\.'; then \
|
|
||||||
# "This package provides support for HKPS keyservers." (GnuPG 1.x only)
|
|
||||||
apt-get install -y --no-install-recommends gnupg-curl; \
|
|
||||||
fi; \
|
|
||||||
rm -rf /var/lib/apt/lists/*; \
|
|
||||||
\
|
|
||||||
dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \
|
|
||||||
wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \
|
|
||||||
wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \
|
|
||||||
export GNUPGHOME="$(mktemp -d)"; \
|
|
||||||
gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \
|
|
||||||
gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \
|
|
||||||
command -v gpgconf && gpgconf --kill all || :; \
|
|
||||||
rm -r "$GNUPGHOME" /usr/local/bin/gosu.asc; \
|
|
||||||
\
|
|
||||||
wget -O /js-yaml.js "https://github.com/nodeca/js-yaml/raw/${JSYAML_VERSION}/dist/js-yaml.js"; \
|
|
||||||
# TODO some sort of download verification here
|
|
||||||
\
|
|
||||||
apt-mark auto '.*' > /dev/null; \
|
|
||||||
apt-mark manual $savedAptMark > /dev/null; \
|
|
||||||
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
|
|
||||||
\
|
|
||||||
# smoke test
|
|
||||||
chmod +x /usr/local/bin/gosu; \
|
|
||||||
gosu --version; \
|
|
||||||
gosu nobody true
|
|
||||||
|
|
||||||
RUN mkdir /docker-entrypoint-initdb.d
|
|
||||||
|
|
||||||
ENV GPG_KEYS=2930ADAE8CAF5059EE73BB4B58712A2291FA4AD5
|
|
||||||
RUN set -ex; export GNUPGHOME="$(mktemp -d)"; for key in $GPG_KEYS; do gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; done; gpg --batch --export $GPG_KEYS > /etc/apt/trusted.gpg.d/mongodb.gpg; command -v gpgconf && gpgconf --kill all || :; rm -r "$GNUPGHOME"; apt-key list
|
|
||||||
|
|
||||||
# Allow build-time overrides (eg. to build image with MongoDB Enterprise version)
|
|
||||||
# Options for MONGO_PACKAGE: mongodb-org OR mongodb-enterprise
|
|
||||||
# Options for MONGO_REPO: repo.mongodb.org OR repo.mongodb.com
|
|
||||||
# Example: docker build --build-arg MONGO_PACKAGE=mongodb-enterprise --build-arg MONGO_REPO=repo.mongodb.com .
|
|
||||||
ARG MONGO_PACKAGE=mongodb-org
|
|
||||||
ARG MONGO_REPO=repo.mongodb.org
|
|
||||||
ENV MONGO_PACKAGE=${MONGO_PACKAGE} MONGO_REPO=${MONGO_REPO}
|
|
||||||
|
|
||||||
ENV MONGO_MAJOR 3.6
|
|
||||||
ENV MONGO_VERSION 3.6.21
|
|
||||||
# bashbrew-architectures:amd64 arm64v8
|
|
||||||
RUN echo "deb http://$MONGO_REPO/apt/debian stretch/${MONGO_PACKAGE%-unstable}/$MONGO_MAJOR main" | tee "/etc/apt/sources.list.d/${MONGO_PACKAGE%-unstable}.list"
|
|
||||||
|
|
||||||
RUN set -x \
|
|
||||||
# installing "mongodb-enterprise" pulls in "tzdata" which prompts for input
|
|
||||||
&& export DEBIAN_FRONTEND=noninteractive \
|
|
||||||
&& apt-get update \
|
|
||||||
&& apt-get install -y \
|
|
||||||
${MONGO_PACKAGE}=$MONGO_VERSION \
|
|
||||||
${MONGO_PACKAGE}-server=$MONGO_VERSION \
|
|
||||||
${MONGO_PACKAGE}-shell=$MONGO_VERSION \
|
|
||||||
${MONGO_PACKAGE}-mongos=$MONGO_VERSION \
|
|
||||||
${MONGO_PACKAGE}-tools=$MONGO_VERSION \
|
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
|
||||||
&& rm -rf /var/lib/mongodb \
|
|
||||||
&& mv /etc/mongod.conf /etc/mongod.conf.orig
|
|
||||||
|
|
||||||
RUN mkdir -p /data/db /data/configdb \
|
|
||||||
&& chown -R mongodb:mongodb /data/db /data/configdb
|
|
||||||
VOLUME /data/db /data/configdb
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# End mongo
|
|
||||||
|
|
||||||
RUN mkdir -p $APP_HOME
|
RUN mkdir -p $APP_HOME
|
||||||
WORKDIR $APP_HOME
|
WORKDIR $APP_HOME
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
@ -127,11 +27,5 @@ ENV NODE_ENV=production
|
||||||
COPY package.json package-lock.json index.js ./
|
COPY package.json package-lock.json index.js ./
|
||||||
RUN npm install --production
|
RUN npm install --production
|
||||||
RUN npm rebuild node-sass
|
RUN npm rebuild node-sass
|
||||||
|
# COPY --from=build $APP_HOME/dist ./dist
|
||||||
|
CMD ["npm", "run", "start:prod"]
|
||||||
COPY dist/static/images/* ./dist/static/images/
|
|
||||||
COPY dist/static/assets ./dist/static/assets
|
|
||||||
|
|
||||||
COPY docker-entrypoint.sh /usr/local/bin/
|
|
||||||
RUN chmod 755 /usr/local/bin/docker-entrypoint.sh
|
|
||||||
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
|
|
||||||
|
|
|
@ -10,8 +10,6 @@ There is a hidden link to have an overview of all users registered on the server
|
||||||
|
|
||||||
# Deployment
|
# Deployment
|
||||||
|
|
||||||
## Manual
|
|
||||||
|
|
||||||
* Push to git (in case linting fails on commit use `git commit --no-verify`)
|
* Push to git (in case linting fails on commit use `git commit --no-verify`)
|
||||||
* Pull on server.
|
* Pull on server.
|
||||||
* `service p5.js-web-editor stop`
|
* `service p5.js-web-editor stop`
|
||||||
|
@ -19,32 +17,15 @@ There is a hidden link to have an overview of all users registered on the server
|
||||||
* `npm run build:client`
|
* `npm run build:client`
|
||||||
* `service p5.js-web-editor start`
|
* `service p5.js-web-editor start`
|
||||||
|
|
||||||
## Docker
|
|
||||||
Branch `single_docker` has a Frankenstein Dockerfile to embed mongo in the single image for deployment to Plex (which doesn't know docker-compose...)
|
|
||||||
|
|
||||||
To build an image called `digitalplayground`:
|
|
||||||
|
|
||||||
`docker build -t digitalplayground .`
|
|
||||||
|
|
||||||
To run it we provide the port to publish, and need to map the volumes of mongo for persistent storage (don't use the tmp folder from the example if you really want persistent storage):
|
|
||||||
|
|
||||||
`docker run -it --env-file .env.production --publish 8001:8000 -v /tmp/dp/db:/data/db -v /tmp/dp/configdb:/data/configdb --name dp_app digitalplayground`
|
|
||||||
|
|
||||||
|
|
||||||
Export the image using:
|
|
||||||
|
|
||||||
`docker save digitalplayground > dp_docker.tar`
|
|
||||||
|
|
||||||
## s3 storage
|
|
||||||
|
|
||||||
Gebruik s3cmd om bucket in te stellen.
|
Gebruik s3cmd om bucket in te stellen.
|
||||||
|
|
||||||
### Make bucket:
|
## Make bucket:
|
||||||
s3cmd mb s3://digitalplayground-p5
|
s3cmd mb s3://digitalplayground-p5
|
||||||
|
|
||||||
### Set the CORS rules
|
## Set the CORS rules
|
||||||
s3cmd -c .s3cfg setcors CORS.xml s3://digitalplayground-p5
|
s3cmd -c .s3cfg setcors CORS.xml s3://digitalplayground-p5
|
||||||
### Delete the CORS rules
|
## Delete the CORS rules
|
||||||
s3cmd -c .s3cfg delcors s3://digitalplayground-p5
|
s3cmd -c .s3cfg delcors s3://digitalplayground-p5
|
||||||
### Get bucket info including CORS rules
|
## Get bucket info including CORS rules
|
||||||
s3cmd -c .s3cfg info s3://digitalplayground-p5
|
s3cmd -c .s3cfg info s3://digitalplayground-p5
|
||||||
|
|
|
@ -65,7 +65,7 @@ App.propTypes = {
|
||||||
App.defaultProps = {
|
App.defaultProps = {
|
||||||
children: null,
|
children: null,
|
||||||
language: null,
|
language: null,
|
||||||
theme: 'dark'
|
theme: 'light'
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
|
|
@ -11,8 +11,8 @@ const initialState = {
|
||||||
textOutput: false,
|
textOutput: false,
|
||||||
gridOutput: false,
|
gridOutput: false,
|
||||||
soundOutput: false,
|
soundOutput: false,
|
||||||
theme: 'dark',
|
theme: 'light',
|
||||||
autorefresh: true,
|
autorefresh: false,
|
||||||
language: 'en-US'
|
language: 'en-US'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ import FooterTabSwitcher from '../../components/mobile/TabSwitcher';
|
||||||
import FooterTab from '../../components/mobile/Tab';
|
import FooterTab from '../../components/mobile/Tab';
|
||||||
import Loader from '../App/components/loader';
|
import Loader from '../App/components/loader';
|
||||||
|
|
||||||
const EXAMPLE_USERNAME = process.env.EXAMPLE_USERNAME || 'digitalplayground';
|
const EXAMPLE_USERNAME = process.env.EXAMPLE_USERNAME || 'p5';
|
||||||
|
|
||||||
// @ghalestrilo 08/13/2020: I'm sorry
|
// @ghalestrilo 08/13/2020: I'm sorry
|
||||||
const ContentWrapper = styled(Content)`
|
const ContentWrapper = styled(Content)`
|
||||||
|
|
|
@ -8,7 +8,7 @@ import Button from '../../../common/Button';
|
||||||
function SignupForm(props) {
|
function SignupForm(props) {
|
||||||
const {
|
const {
|
||||||
fields: {
|
fields: {
|
||||||
username, /* email, */ password, confirmPassword
|
username, email, password, confirmPassword
|
||||||
},
|
},
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
submitting,
|
submitting,
|
||||||
|
@ -33,7 +33,7 @@ function SignupForm(props) {
|
||||||
<span className="form-error">{username.error}</span>
|
<span className="form-error">{username.error}</span>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
{/* <p className="form__field">
|
<p className="form__field">
|
||||||
<label htmlFor="email" className="form__label">{props.t('SignupForm.Email')}</label>
|
<label htmlFor="email" className="form__label">{props.t('SignupForm.Email')}</label>
|
||||||
<input
|
<input
|
||||||
className="form__input"
|
className="form__input"
|
||||||
|
@ -45,7 +45,7 @@ function SignupForm(props) {
|
||||||
{email.touched && email.error && (
|
{email.touched && email.error && (
|
||||||
<span className="form-error">{email.error}</span>
|
<span className="form-error">{email.error}</span>
|
||||||
)}
|
)}
|
||||||
</p> */}
|
</p>
|
||||||
<p className="form__field">
|
<p className="form__field">
|
||||||
<label htmlFor="password" className="form__label">{props.t('SignupForm.Password')}</label>
|
<label htmlFor="password" className="form__label">{props.t('SignupForm.Password')}</label>
|
||||||
<input
|
<input
|
||||||
|
@ -84,7 +84,7 @@ function SignupForm(props) {
|
||||||
SignupForm.propTypes = {
|
SignupForm.propTypes = {
|
||||||
fields: PropTypes.shape({
|
fields: PropTypes.shape({
|
||||||
username: PropTypes.object.isRequired, // eslint-disable-line
|
username: PropTypes.object.isRequired, // eslint-disable-line
|
||||||
// email: PropTypes.object.isRequired, // eslint-disable-line
|
email: PropTypes.object.isRequired, // eslint-disable-line
|
||||||
password: PropTypes.object.isRequired, // eslint-disable-line
|
password: PropTypes.object.isRequired, // eslint-disable-line
|
||||||
confirmPassword: PropTypes.object.isRequired, // eslint-disable-line
|
confirmPassword: PropTypes.object.isRequired, // eslint-disable-line
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
|
|
|
@ -9,9 +9,9 @@ import * as UserActions from '../actions';
|
||||||
import SignupForm from '../components/SignupForm';
|
import SignupForm from '../components/SignupForm';
|
||||||
import apiClient from '../../../utils/apiClient';
|
import apiClient from '../../../utils/apiClient';
|
||||||
import { validateSignup } from '../../../utils/reduxFormUtils';
|
import { validateSignup } from '../../../utils/reduxFormUtils';
|
||||||
// import SocialAuthButton from '../components/SocialAuthButton';
|
import SocialAuthButton from '../components/SocialAuthButton';
|
||||||
import Nav from '../../../components/Nav';
|
import Nav from '../../../components/Nav';
|
||||||
// import ResponsiveForm from '../components/ResponsiveForm';
|
import ResponsiveForm from '../components/ResponsiveForm';
|
||||||
|
|
||||||
|
|
||||||
class SignupView extends React.Component {
|
class SignupView extends React.Component {
|
||||||
|
@ -123,9 +123,9 @@ SignupView.defaultProps = {
|
||||||
|
|
||||||
export default withTranslation()(reduxForm({
|
export default withTranslation()(reduxForm({
|
||||||
form: 'signup',
|
form: 'signup',
|
||||||
fields: ['username', /* 'email', */ 'password', 'confirmPassword'],
|
fields: ['username', 'email', 'password', 'confirmPassword'],
|
||||||
onSubmitFail,
|
onSubmitFail,
|
||||||
validate: validateSignup,
|
validate: validateSignup,
|
||||||
asyncValidate,
|
asyncValidate,
|
||||||
asyncBlurFields: ['username'/* , 'email' */]
|
asyncBlurFields: ['username', 'email']
|
||||||
}, mapStateToProps, mapDispatchToProps)(SignupView));
|
}, mapStateToProps, mapDispatchToProps)(SignupView));
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
$base-font-size: 20;
|
$base-font-size: 12;
|
||||||
|
|
||||||
//colors
|
//colors
|
||||||
$p5js-pink: #FFE117; /*DP Colours*/
|
$p5js-pink: #FFE117; /*DP Colours*/
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
.CodeMirror {
|
.CodeMirror {
|
||||||
font-family: Inconsolata, monospace;
|
font-family: Inconsolata, monospace;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
font-size:$base-font-size !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.CodeMirror-linenumbers {
|
.CodeMirror-linenumbers {
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.form__label {
|
.form__label {
|
||||||
font-size: #{16 / $base-font-size}rem;
|
font-size: #{12 / $base-font-size}rem;
|
||||||
margin-top: #{25 / $base-font-size}rem;
|
margin-top: #{25 / $base-font-size}rem;
|
||||||
margin-bottom: #{7 / $base-font-size}rem;
|
margin-bottom: #{7 / $base-font-size}rem;
|
||||||
display: block;
|
display: block;
|
||||||
|
|
|
@ -158,7 +158,7 @@
|
||||||
color: getThemifyVariable('secondary-text-color');
|
color: getThemifyVariable('secondary-text-color');
|
||||||
}
|
}
|
||||||
margin-left: #{5 / $base-font-size}rem;
|
margin-left: #{5 / $base-font-size}rem;
|
||||||
font-size: #{15 / $base-font-size}rem;
|
font-size: #{12 / $base-font-size}rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar__edit-name-button {
|
.toolbar__edit-name-button {
|
||||||
|
|
|
@ -28,11 +28,9 @@ function validateNameEmail(formProps, errors) {
|
||||||
errors.username = i18n.t('ReduxFormUtils.errorValidUsername');
|
errors.username = i18n.t('ReduxFormUtils.errorValidUsername');
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (!formProps.email) {
|
if (!formProps.email) {
|
||||||
// errors.email = i18n.t('ReduxFormUtils.errorEmptyEmail');
|
errors.email = i18n.t('ReduxFormUtils.errorEmptyEmail');
|
||||||
// } else
|
} else if (
|
||||||
if (
|
|
||||||
formProps.email &&
|
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
!formProps.email.match(EMAIL_REGEX)) {
|
!formProps.email.match(EMAIL_REGEX)) {
|
||||||
errors.email = i18n.t('ReduxFormUtils.errorInvalidEmail');
|
errors.email = i18n.t('ReduxFormUtils.errorInvalidEmail');
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
echo "HALLO!"
|
|
||||||
echo "Starting the mongodb daemon"
|
|
||||||
/usr/bin/mongod --fork --syslog
|
|
||||||
|
|
||||||
# echo "navigating to volume /var/www"
|
|
||||||
# cd /var/www
|
|
||||||
# echo "Creating soft link"
|
|
||||||
# ln -s /opt/mysite mysite
|
|
||||||
|
|
||||||
# a2enmod headers
|
|
||||||
# service apache2 restart
|
|
||||||
|
|
||||||
# a2ensite mysite.conf
|
|
||||||
# a2dissite 000-default.conf
|
|
||||||
# service apache2 reload
|
|
||||||
|
|
||||||
if [ -z "$1" ]
|
|
||||||
then
|
|
||||||
exec npm run start:prod
|
|
||||||
else
|
|
||||||
exec "$1"
|
|
||||||
fi
|
|
|
@ -24,7 +24,7 @@ passport.deserializeUser((id, done) => {
|
||||||
* Sign in using Email/Username and Password.
|
* Sign in using Email/Username and Password.
|
||||||
*/
|
*/
|
||||||
passport.use(new LocalStrategy({ usernameField: 'email' }, (email, password, done) => {
|
passport.use(new LocalStrategy({ usernameField: 'email' }, (email, password, done) => {
|
||||||
User.findByUsername(email)
|
User.findByEmailOrUsername(email)
|
||||||
.then((user) => { // eslint-disable-line consistent-return
|
.then((user) => { // eslint-disable-line consistent-return
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return done(null, false, { msg: `Email ${email} not found.` });
|
return done(null, false, { msg: `Email ${email} not found.` });
|
||||||
|
|
|
@ -12,7 +12,7 @@ export * from './user.controller/apiKey';
|
||||||
|
|
||||||
export function userResponse(user) {
|
export function userResponse(user) {
|
||||||
return {
|
return {
|
||||||
// email: user.email,
|
email: user.email,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
preferences: user.preferences,
|
preferences: user.preferences,
|
||||||
apiKeys: user.apiKeys,
|
apiKeys: user.apiKeys,
|
||||||
|
@ -36,32 +36,31 @@ export function findUserByUsername(username, cb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createUser(req, res, next) {
|
export function createUser(req, res, next) {
|
||||||
const { username, _ } = req.body;
|
const { username, email } = req.body;
|
||||||
const { password } = req.body;
|
const { password } = req.body;
|
||||||
// const emailLowerCase = email ? email.toLowerCase() : null;
|
const emailLowerCase = email.toLowerCase();
|
||||||
const EMAIL_VERIFY_TOKEN_EXPIRY_TIME = Date.now() + (3600000 * 24); // 24 hours
|
const EMAIL_VERIFY_TOKEN_EXPIRY_TIME = Date.now() + (3600000 * 24); // 24 hours
|
||||||
random((tokenError, token) => {
|
random((tokenError, token) => {
|
||||||
const user = new User({
|
const user = new User({
|
||||||
username,
|
username,
|
||||||
// email: emailLowerCase,
|
email: emailLowerCase,
|
||||||
password,
|
password,
|
||||||
verified: User.EmailConfirmation.Sent,
|
verified: User.EmailConfirmation.Sent,
|
||||||
verifiedToken: token,
|
verifiedToken: token,
|
||||||
verifiedTokenExpires: EMAIL_VERIFY_TOKEN_EXPIRY_TIME,
|
verifiedTokenExpires: EMAIL_VERIFY_TOKEN_EXPIRY_TIME,
|
||||||
});
|
});
|
||||||
|
|
||||||
User.findByUsername(username, (err, existingUser) => {
|
User.findByEmailAndUsername(email, username, (err, existingUser) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
res.status(404).send({ error: err });
|
res.status(404).send({ error: err });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existingUser) {
|
if (existingUser) {
|
||||||
const fieldInUse = 'Username';
|
const fieldInUse = existingUser.email.toLowerCase() === emailLowerCase ? 'Email' : 'Username';
|
||||||
res.status(422).send({ error: `${fieldInUse} is in use` });
|
res.status(422).send({ error: `${fieldInUse} is in use` });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.save((saveErr) => {
|
user.save((saveErr) => {
|
||||||
if (saveErr) {
|
if (saveErr) {
|
||||||
next(saveErr);
|
next(saveErr);
|
||||||
|
@ -74,17 +73,17 @@ export function createUser(req, res, next) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const protocol = process.env.NODE_ENV === 'production' ? 'https' : 'http';
|
const protocol = process.env.NODE_ENV === 'production' ? 'https' : 'http';
|
||||||
// const mailOptions = renderEmailConfirmation({
|
const mailOptions = renderEmailConfirmation({
|
||||||
// body: {
|
body: {
|
||||||
// domain: `${protocol}://${req.headers.host}`,
|
domain: `${protocol}://${req.headers.host}`,
|
||||||
// link: `${protocol}://${req.headers.host}/verify?t=${token}`
|
link: `${protocol}://${req.headers.host}/verify?t=${token}`
|
||||||
// },
|
},
|
||||||
// to: req.user.email,
|
to: req.user.email,
|
||||||
// });
|
});
|
||||||
|
|
||||||
// mail.send(mailOptions, (mailErr, result) => { // eslint-disable-line no-unused-vars
|
mail.send(mailOptions, (mailErr, result) => { // eslint-disable-line no-unused-vars
|
||||||
res.json(userResponse(req.user));
|
res.json(userResponse(req.user));
|
||||||
// });
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -143,19 +142,18 @@ export function resetPasswordInitiate(req, res) {
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
random,
|
random,
|
||||||
(token, done) => {
|
(token, done) => {
|
||||||
// disable since we don't use email
|
User.findByEmail(req.body.email, (err, user) => {
|
||||||
// User.findByEmail(req.body.email, (err, user) => {
|
if (!user) {
|
||||||
// if (!user) {
|
res.json({ success: true, message: 'If the email is registered with the editor, an email has been sent.' });
|
||||||
// res.json({ success: true, message: 'If the email is registered with the editor, an email has been sent.' });
|
return;
|
||||||
// return;
|
}
|
||||||
// }
|
user.resetPasswordToken = token;
|
||||||
// user.resetPasswordToken = token;
|
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
|
||||||
// user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
|
|
||||||
|
|
||||||
// user.save((saveErr) => {
|
user.save((saveErr) => {
|
||||||
// done(saveErr, token, user);
|
done(saveErr, token, user);
|
||||||
// });
|
});
|
||||||
// });
|
});
|
||||||
},
|
},
|
||||||
(token, user, done) => {
|
(token, user, done) => {
|
||||||
const protocol = process.env.NODE_ENV === 'production' ? 'https' : 'http';
|
const protocol = process.env.NODE_ENV === 'production' ? 'https' : 'http';
|
||||||
|
|
|
@ -50,7 +50,7 @@ const userSchema = new Schema({
|
||||||
verifiedToken: String,
|
verifiedToken: String,
|
||||||
verifiedTokenExpires: Date,
|
verifiedTokenExpires: Date,
|
||||||
github: { type: String },
|
github: { type: String },
|
||||||
email: { type: String },
|
email: { type: String, unique: true },
|
||||||
tokens: Array,
|
tokens: Array,
|
||||||
apiKeys: { type: [apiKeySchema] },
|
apiKeys: { type: [apiKeySchema] },
|
||||||
preferences: {
|
preferences: {
|
||||||
|
@ -64,8 +64,8 @@ const userSchema = new Schema({
|
||||||
textOutput: { type: Boolean, default: false },
|
textOutput: { type: Boolean, default: false },
|
||||||
gridOutput: { type: Boolean, default: false },
|
gridOutput: { type: Boolean, default: false },
|
||||||
soundOutput: { type: Boolean, default: false },
|
soundOutput: { type: Boolean, default: false },
|
||||||
theme: { type: String, default: 'dark' },
|
theme: { type: String, default: 'light' },
|
||||||
autorefresh: { type: Boolean, default: true },
|
autorefresh: { type: Boolean, default: false },
|
||||||
language: { type: String, default: 'en-US' }
|
language: { type: String, default: 'en-US' }
|
||||||
},
|
},
|
||||||
totalSize: { type: Number, default: 0 }
|
totalSize: { type: Number, default: 0 }
|
||||||
|
@ -192,10 +192,10 @@ userSchema.statics.findByUsername = function findByUsername(username, cb) {
|
||||||
* @return {Promise<Object>} - Returns Promise fulfilled by User document
|
* @return {Promise<Object>} - Returns Promise fulfilled by User document
|
||||||
*/
|
*/
|
||||||
userSchema.statics.findByEmailOrUsername = function findByEmailOrUsername(value, cb) {
|
userSchema.statics.findByEmailOrUsername = function findByEmailOrUsername(value, cb) {
|
||||||
// const isEmail = value.indexOf('@') > -1;
|
const isEmail = value.indexOf('@') > -1;
|
||||||
// if (isEmail) {
|
if (isEmail) {
|
||||||
// return this.findByEmail(value, cb);
|
return this.findByEmail(value, cb);
|
||||||
// }
|
}
|
||||||
return this.findByUsername(value, cb);
|
return this.findByUsername(value, cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -210,11 +210,11 @@ userSchema.statics.findByEmailOrUsername = function findByEmailOrUsername(value,
|
||||||
* @return {Promise<Object>} - Returns Promise fulfilled by User document
|
* @return {Promise<Object>} - Returns Promise fulfilled by User document
|
||||||
*/
|
*/
|
||||||
userSchema.statics.findByEmailAndUsername = function findByEmailAndUsername(email, username, cb) {
|
userSchema.statics.findByEmailAndUsername = function findByEmailAndUsername(email, username, cb) {
|
||||||
const query = { username // override username only as we don't want to register email addresses
|
const query = {
|
||||||
// $or: [
|
$or: [
|
||||||
// { email },
|
{ email },
|
||||||
// { username }
|
{ username }
|
||||||
// ]
|
]
|
||||||
};
|
};
|
||||||
return this.findOne(query).collation({ locale: 'en', strength: 2 }).exec(cb);
|
return this.findOne(query).collation({ locale: 'en', strength: 2 }).exec(cb);
|
||||||
};
|
};
|
||||||
|
@ -224,5 +224,4 @@ userSchema.statics.EmailConfirmation = EmailConfirmationStates;
|
||||||
userSchema.index({ username: 1 }, { collation: { locale: 'en', strength: 2 } });
|
userSchema.index({ username: 1 }, { collation: { locale: 'en', strength: 2 } });
|
||||||
userSchema.index({ email: 1 }, { collation: { locale: 'en', strength: 2 } });
|
userSchema.index({ email: 1 }, { collation: { locale: 'en', strength: 2 } });
|
||||||
|
|
||||||
|
|
||||||
export default mongoose.model('User', userSchema);
|
export default mongoose.model('User', userSchema);
|
||||||
|
|
|
@ -191,26 +191,12 @@ app.use('/api', (error, req, res, next) => {
|
||||||
|
|
||||||
// overview of users:
|
// overview of users:
|
||||||
app.get('/users', (req, res) => {
|
app.get('/users', (req, res) => {
|
||||||
// hacky migration here
|
|
||||||
User.collection.getIndexes(({full: true})).then((indexes) =>{
|
|
||||||
console.log('indexes', indexes);
|
|
||||||
// migrate unique
|
|
||||||
indexes.forEach(function (index) {
|
|
||||||
if(index.name !=='email_1') return;
|
|
||||||
if(!index.unique) return;
|
|
||||||
console.log('Drop index!', index);
|
|
||||||
User.collection.dropIndex('email_1');
|
|
||||||
console.log('Recreate index!');
|
|
||||||
User.collection.createIndex({ email: 1 }, { collation: { locale: 'en', strength: 2 } });
|
|
||||||
|
|
||||||
});
|
|
||||||
})
|
|
||||||
// let results = [];
|
// let results = [];
|
||||||
User.find({}).sort({ createdAt: -1 }).exec()
|
User.find({}).sort({ createdAt: -1 }).exec()
|
||||||
.then((users) => {
|
.then((users) => {
|
||||||
// const usernames = users.map((user) => user.username);
|
const usernames = users.map((user) => user.username);
|
||||||
let names = "<ul>";
|
let names = "<ul>";
|
||||||
users.forEach((user) => names += `<li><a href="/${user.username}/sketches">${user.username}</a> - ${user.createdAt.toGMTString()}</li>`);
|
usernames.forEach((username) => names += `<li><a href="/${username}/sketches">${username}</a></li>`);
|
||||||
names += "</ul>";
|
names += "</ul>";
|
||||||
res.send(names);
|
res.send(names);
|
||||||
});
|
});
|
||||||
|
|
|
@ -29,7 +29,7 @@ export function renderIndex() {
|
||||||
window.process.env.CLIENT = true;
|
window.process.env.CLIENT = true;
|
||||||
window.process.env.LOGIN_ENABLED = ${process.env.LOGIN_ENABLED === 'false' ? false : true};
|
window.process.env.LOGIN_ENABLED = ${process.env.LOGIN_ENABLED === 'false' ? false : true};
|
||||||
window.process.env.EXAMPLES_ENABLED = ${process.env.EXAMPLES_ENABLED === 'false' ? false : true};
|
window.process.env.EXAMPLES_ENABLED = ${process.env.EXAMPLES_ENABLED === 'false' ? false : true};
|
||||||
window.process.env.EXAMPLE_USERNAME = '${process.env.EXAMPLE_USERNAME || 'digitalplayground'}';
|
window.process.env.EXAMPLE_USERNAME = '${process.env.EXAMPLE_USERNAME || 'p5'}';
|
||||||
window.process.env.UI_ACCESS_TOKEN_ENABLED = ${process.env.UI_ACCESS_TOKEN_ENABLED === 'false' ? false : true};
|
window.process.env.UI_ACCESS_TOKEN_ENABLED = ${process.env.UI_ACCESS_TOKEN_ENABLED === 'false' ? false : true};
|
||||||
window.process.env.UI_COLLECTIONS_ENABLED = ${process.env.UI_COLLECTIONS_ENABLED === 'false' ? false : true};
|
window.process.env.UI_COLLECTIONS_ENABLED = ${process.env.UI_COLLECTIONS_ENABLED === 'false' ? false : true};
|
||||||
window.process.env.UPLOAD_LIMIT = ${process.env.UPLOAD_LIMIT ? `${process.env.UPLOAD_LIMIT}` : undefined};
|
window.process.env.UPLOAD_LIMIT = ${process.env.UPLOAD_LIMIT ? `${process.env.UPLOAD_LIMIT}` : undefined};
|
||||||
|
|
Loading…
Reference in a new issue