Compare commits
6 commits
dev/prod
...
single_doc
Author | SHA1 | Date | |
---|---|---|---|
|
99c786ced5 | ||
|
f820a8a85f | ||
|
743f08189c | ||
|
34aab31921 | ||
|
3849566772 | ||
|
db151aca5c |
18 changed files with 238 additions and 67 deletions
110
Dockerfile
110
Dockerfile
|
@ -1,6 +1,106 @@
|
|||
FROM node:12.16.1 as base
|
||||
ENV APP_HOME=/usr/src/app \
|
||||
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
|
||||
WORKDIR $APP_HOME
|
||||
EXPOSE 8000
|
||||
|
@ -27,5 +127,11 @@ ENV NODE_ENV=production
|
|||
COPY package.json package-lock.json index.js ./
|
||||
RUN npm install --production
|
||||
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,6 +10,8 @@ There is a hidden link to have an overview of all users registered on the server
|
|||
|
||||
# Deployment
|
||||
|
||||
## Manual
|
||||
|
||||
* Push to git (in case linting fails on commit use `git commit --no-verify`)
|
||||
* Pull on server.
|
||||
* `service p5.js-web-editor stop`
|
||||
|
@ -17,15 +19,32 @@ There is a hidden link to have an overview of all users registered on the server
|
|||
* `npm run build:client`
|
||||
* `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.
|
||||
|
||||
## Make bucket:
|
||||
### Make bucket:
|
||||
s3cmd mb s3://digitalplayground-p5
|
||||
|
||||
## Set the CORS rules
|
||||
### Set the CORS rules
|
||||
s3cmd -c .s3cfg setcors CORS.xml s3://digitalplayground-p5
|
||||
## Delete the CORS rules
|
||||
### Delete the CORS rules
|
||||
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
|
||||
|
|
|
@ -65,7 +65,7 @@ App.propTypes = {
|
|||
App.defaultProps = {
|
||||
children: null,
|
||||
language: null,
|
||||
theme: 'light'
|
||||
theme: 'dark'
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
|
|
|
@ -11,8 +11,8 @@ const initialState = {
|
|||
textOutput: false,
|
||||
gridOutput: false,
|
||||
soundOutput: false,
|
||||
theme: 'light',
|
||||
autorefresh: false,
|
||||
theme: 'dark',
|
||||
autorefresh: true,
|
||||
language: 'en-US'
|
||||
};
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import FooterTabSwitcher from '../../components/mobile/TabSwitcher';
|
|||
import FooterTab from '../../components/mobile/Tab';
|
||||
import Loader from '../App/components/loader';
|
||||
|
||||
const EXAMPLE_USERNAME = process.env.EXAMPLE_USERNAME || 'p5';
|
||||
const EXAMPLE_USERNAME = process.env.EXAMPLE_USERNAME || 'digitalplayground';
|
||||
|
||||
// @ghalestrilo 08/13/2020: I'm sorry
|
||||
const ContentWrapper = styled(Content)`
|
||||
|
|
|
@ -8,7 +8,7 @@ import Button from '../../../common/Button';
|
|||
function SignupForm(props) {
|
||||
const {
|
||||
fields: {
|
||||
username, email, password, confirmPassword
|
||||
username, /* email, */ password, confirmPassword
|
||||
},
|
||||
handleSubmit,
|
||||
submitting,
|
||||
|
@ -33,7 +33,7 @@ function SignupForm(props) {
|
|||
<span className="form-error">{username.error}</span>
|
||||
)}
|
||||
</p>
|
||||
<p className="form__field">
|
||||
{/* <p className="form__field">
|
||||
<label htmlFor="email" className="form__label">{props.t('SignupForm.Email')}</label>
|
||||
<input
|
||||
className="form__input"
|
||||
|
@ -45,7 +45,7 @@ function SignupForm(props) {
|
|||
{email.touched && email.error && (
|
||||
<span className="form-error">{email.error}</span>
|
||||
)}
|
||||
</p>
|
||||
</p> */}
|
||||
<p className="form__field">
|
||||
<label htmlFor="password" className="form__label">{props.t('SignupForm.Password')}</label>
|
||||
<input
|
||||
|
@ -84,7 +84,7 @@ function SignupForm(props) {
|
|||
SignupForm.propTypes = {
|
||||
fields: PropTypes.shape({
|
||||
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
|
||||
confirmPassword: PropTypes.object.isRequired, // eslint-disable-line
|
||||
}).isRequired,
|
||||
|
|
|
@ -9,9 +9,9 @@ import * as UserActions from '../actions';
|
|||
import SignupForm from '../components/SignupForm';
|
||||
import apiClient from '../../../utils/apiClient';
|
||||
import { validateSignup } from '../../../utils/reduxFormUtils';
|
||||
import SocialAuthButton from '../components/SocialAuthButton';
|
||||
// import SocialAuthButton from '../components/SocialAuthButton';
|
||||
import Nav from '../../../components/Nav';
|
||||
import ResponsiveForm from '../components/ResponsiveForm';
|
||||
// import ResponsiveForm from '../components/ResponsiveForm';
|
||||
|
||||
|
||||
class SignupView extends React.Component {
|
||||
|
@ -123,9 +123,9 @@ SignupView.defaultProps = {
|
|||
|
||||
export default withTranslation()(reduxForm({
|
||||
form: 'signup',
|
||||
fields: ['username', 'email', 'password', 'confirmPassword'],
|
||||
fields: ['username', /* 'email', */ 'password', 'confirmPassword'],
|
||||
onSubmitFail,
|
||||
validate: validateSignup,
|
||||
asyncValidate,
|
||||
asyncBlurFields: ['username', 'email']
|
||||
asyncBlurFields: ['username'/* , 'email' */]
|
||||
}, mapStateToProps, mapDispatchToProps)(SignupView));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
$base-font-size: 12;
|
||||
$base-font-size: 20;
|
||||
|
||||
//colors
|
||||
$p5js-pink: #FFE117; /*DP Colours*/
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
.CodeMirror {
|
||||
font-family: Inconsolata, monospace;
|
||||
height: 100%;
|
||||
font-size:$base-font-size !important;
|
||||
}
|
||||
|
||||
.CodeMirror-linenumbers {
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
}
|
||||
|
||||
.form__label {
|
||||
font-size: #{12 / $base-font-size}rem;
|
||||
font-size: #{16 / $base-font-size}rem;
|
||||
margin-top: #{25 / $base-font-size}rem;
|
||||
margin-bottom: #{7 / $base-font-size}rem;
|
||||
display: block;
|
||||
|
|
|
@ -158,7 +158,7 @@
|
|||
color: getThemifyVariable('secondary-text-color');
|
||||
}
|
||||
margin-left: #{5 / $base-font-size}rem;
|
||||
font-size: #{12 / $base-font-size}rem;
|
||||
font-size: #{15 / $base-font-size}rem;
|
||||
}
|
||||
|
||||
.toolbar__edit-name-button {
|
||||
|
|
|
@ -28,9 +28,11 @@ function validateNameEmail(formProps, errors) {
|
|||
errors.username = i18n.t('ReduxFormUtils.errorValidUsername');
|
||||
}
|
||||
|
||||
if (!formProps.email) {
|
||||
errors.email = i18n.t('ReduxFormUtils.errorEmptyEmail');
|
||||
} else if (
|
||||
// if (!formProps.email) {
|
||||
// errors.email = i18n.t('ReduxFormUtils.errorEmptyEmail');
|
||||
// } else
|
||||
if (
|
||||
formProps.email &&
|
||||
// eslint-disable-next-line max-len
|
||||
!formProps.email.match(EMAIL_REGEX)) {
|
||||
errors.email = i18n.t('ReduxFormUtils.errorInvalidEmail');
|
||||
|
|
26
docker-entrypoint.sh
Normal file
26
docker-entrypoint.sh
Normal file
|
@ -0,0 +1,26 @@
|
|||
#!/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.
|
||||
*/
|
||||
passport.use(new LocalStrategy({ usernameField: 'email' }, (email, password, done) => {
|
||||
User.findByEmailOrUsername(email)
|
||||
User.findByUsername(email)
|
||||
.then((user) => { // eslint-disable-line consistent-return
|
||||
if (!user) {
|
||||
return done(null, false, { msg: `Email ${email} not found.` });
|
||||
|
|
|
@ -12,7 +12,7 @@ export * from './user.controller/apiKey';
|
|||
|
||||
export function userResponse(user) {
|
||||
return {
|
||||
email: user.email,
|
||||
// email: user.email,
|
||||
username: user.username,
|
||||
preferences: user.preferences,
|
||||
apiKeys: user.apiKeys,
|
||||
|
@ -36,31 +36,32 @@ export function findUserByUsername(username, cb) {
|
|||
}
|
||||
|
||||
export function createUser(req, res, next) {
|
||||
const { username, email } = req.body;
|
||||
const { username, _ } = req.body;
|
||||
const { password } = req.body;
|
||||
const emailLowerCase = email.toLowerCase();
|
||||
// const emailLowerCase = email ? email.toLowerCase() : null;
|
||||
const EMAIL_VERIFY_TOKEN_EXPIRY_TIME = Date.now() + (3600000 * 24); // 24 hours
|
||||
random((tokenError, token) => {
|
||||
const user = new User({
|
||||
username,
|
||||
email: emailLowerCase,
|
||||
// email: emailLowerCase,
|
||||
password,
|
||||
verified: User.EmailConfirmation.Sent,
|
||||
verifiedToken: token,
|
||||
verifiedTokenExpires: EMAIL_VERIFY_TOKEN_EXPIRY_TIME,
|
||||
});
|
||||
|
||||
User.findByEmailAndUsername(email, username, (err, existingUser) => {
|
||||
User.findByUsername(username, (err, existingUser) => {
|
||||
if (err) {
|
||||
res.status(404).send({ error: err });
|
||||
return;
|
||||
}
|
||||
|
||||
if (existingUser) {
|
||||
const fieldInUse = existingUser.email.toLowerCase() === emailLowerCase ? 'Email' : 'Username';
|
||||
const fieldInUse = 'Username';
|
||||
res.status(422).send({ error: `${fieldInUse} is in use` });
|
||||
return;
|
||||
}
|
||||
|
||||
user.save((saveErr) => {
|
||||
if (saveErr) {
|
||||
next(saveErr);
|
||||
|
@ -73,17 +74,17 @@ export function createUser(req, res, next) {
|
|||
}
|
||||
|
||||
const protocol = process.env.NODE_ENV === 'production' ? 'https' : 'http';
|
||||
const mailOptions = renderEmailConfirmation({
|
||||
body: {
|
||||
domain: `${protocol}://${req.headers.host}`,
|
||||
link: `${protocol}://${req.headers.host}/verify?t=${token}`
|
||||
},
|
||||
to: req.user.email,
|
||||
});
|
||||
// const mailOptions = renderEmailConfirmation({
|
||||
// body: {
|
||||
// domain: `${protocol}://${req.headers.host}`,
|
||||
// link: `${protocol}://${req.headers.host}/verify?t=${token}`
|
||||
// },
|
||||
// to: req.user.email,
|
||||
// });
|
||||
|
||||
mail.send(mailOptions, (mailErr, result) => { // eslint-disable-line no-unused-vars
|
||||
res.json(userResponse(req.user));
|
||||
});
|
||||
// mail.send(mailOptions, (mailErr, result) => { // eslint-disable-line no-unused-vars
|
||||
res.json(userResponse(req.user));
|
||||
// });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -142,18 +143,19 @@ export function resetPasswordInitiate(req, res) {
|
|||
async.waterfall([
|
||||
random,
|
||||
(token, done) => {
|
||||
User.findByEmail(req.body.email, (err, user) => {
|
||||
if (!user) {
|
||||
res.json({ success: true, message: 'If the email is registered with the editor, an email has been sent.' });
|
||||
return;
|
||||
}
|
||||
user.resetPasswordToken = token;
|
||||
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
|
||||
// disable since we don't use email
|
||||
// User.findByEmail(req.body.email, (err, user) => {
|
||||
// if (!user) {
|
||||
// res.json({ success: true, message: 'If the email is registered with the editor, an email has been sent.' });
|
||||
// return;
|
||||
// }
|
||||
// user.resetPasswordToken = token;
|
||||
// user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
|
||||
|
||||
user.save((saveErr) => {
|
||||
done(saveErr, token, user);
|
||||
});
|
||||
});
|
||||
// user.save((saveErr) => {
|
||||
// done(saveErr, token, user);
|
||||
// });
|
||||
// });
|
||||
},
|
||||
(token, user, done) => {
|
||||
const protocol = process.env.NODE_ENV === 'production' ? 'https' : 'http';
|
||||
|
|
|
@ -50,7 +50,7 @@ const userSchema = new Schema({
|
|||
verifiedToken: String,
|
||||
verifiedTokenExpires: Date,
|
||||
github: { type: String },
|
||||
email: { type: String, unique: true },
|
||||
email: { type: String },
|
||||
tokens: Array,
|
||||
apiKeys: { type: [apiKeySchema] },
|
||||
preferences: {
|
||||
|
@ -64,8 +64,8 @@ const userSchema = new Schema({
|
|||
textOutput: { type: Boolean, default: false },
|
||||
gridOutput: { type: Boolean, default: false },
|
||||
soundOutput: { type: Boolean, default: false },
|
||||
theme: { type: String, default: 'light' },
|
||||
autorefresh: { type: Boolean, default: false },
|
||||
theme: { type: String, default: 'dark' },
|
||||
autorefresh: { type: Boolean, default: true },
|
||||
language: { type: String, default: 'en-US' }
|
||||
},
|
||||
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
|
||||
*/
|
||||
userSchema.statics.findByEmailOrUsername = function findByEmailOrUsername(value, cb) {
|
||||
const isEmail = value.indexOf('@') > -1;
|
||||
if (isEmail) {
|
||||
return this.findByEmail(value, cb);
|
||||
}
|
||||
// const isEmail = value.indexOf('@') > -1;
|
||||
// if (isEmail) {
|
||||
// return this.findByEmail(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
|
||||
*/
|
||||
userSchema.statics.findByEmailAndUsername = function findByEmailAndUsername(email, username, cb) {
|
||||
const query = {
|
||||
$or: [
|
||||
{ email },
|
||||
{ username }
|
||||
]
|
||||
const query = { username // override username only as we don't want to register email addresses
|
||||
// $or: [
|
||||
// { email },
|
||||
// { username }
|
||||
// ]
|
||||
};
|
||||
return this.findOne(query).collation({ locale: 'en', strength: 2 }).exec(cb);
|
||||
};
|
||||
|
@ -224,4 +224,5 @@ userSchema.statics.EmailConfirmation = EmailConfirmationStates;
|
|||
userSchema.index({ username: 1 }, { collation: { locale: 'en', strength: 2 } });
|
||||
userSchema.index({ email: 1 }, { collation: { locale: 'en', strength: 2 } });
|
||||
|
||||
|
||||
export default mongoose.model('User', userSchema);
|
||||
|
|
|
@ -191,12 +191,26 @@ app.use('/api', (error, req, res, next) => {
|
|||
|
||||
// overview of users:
|
||||
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 = [];
|
||||
User.find({}).sort({ createdAt: -1 }).exec()
|
||||
.then((users) => {
|
||||
const usernames = users.map((user) => user.username);
|
||||
// const usernames = users.map((user) => user.username);
|
||||
let names = "<ul>";
|
||||
usernames.forEach((username) => names += `<li><a href="/${username}/sketches">${username}</a></li>`);
|
||||
users.forEach((user) => names += `<li><a href="/${user.username}/sketches">${user.username}</a> - ${user.createdAt.toGMTString()}</li>`);
|
||||
names += "</ul>";
|
||||
res.send(names);
|
||||
});
|
||||
|
|
|
@ -29,7 +29,7 @@ export function renderIndex() {
|
|||
window.process.env.CLIENT = 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.EXAMPLE_USERNAME = '${process.env.EXAMPLE_USERNAME || 'p5'}';
|
||||
window.process.env.EXAMPLE_USERNAME = '${process.env.EXAMPLE_USERNAME || 'digitalplayground'}';
|
||||
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.UPLOAD_LIMIT = ${process.env.UPLOAD_LIMIT ? `${process.env.UPLOAD_LIMIT}` : undefined};
|
||||
|
|
Loading…
Reference in a new issue