Skip to content

Commit

Permalink
Attribute editing fix (#37)
Browse files Browse the repository at this point in the history
* Create basic endpoint skeleton

* get endpoint 500 error

* Fix routing

* Get member endpoint to work

* Return more fields from endpoint

* Return object id from endpoint

* Add filterSensitiveInfo util

* Give all non-required Member fields a default of null

* Move passport-setup to utils

* Remove console.log

* Add members endpoints

* Fix filterSensitiveInfo util

* Use passport-setup.js in utils

* Use auth endpoint

* Move /api/auth/user to /api/members/current

* Add omit fields to GET /:memberId

* Change current user endpoint in frontend

* Add more auth utils

* Use isDirector from module in members routes

* Change level default in model back to TBD

* Add level priority explanation

* Add detailed permission checking in members endpoint

* Fix difference function

* Fix typos in user-utils

* Add _id as neverEditable field

* Fix allFields not being checked correctly

* Filter viewable fields when returning from PUT

* Pull enum options from backend

* Add status options to endpoint

* Disable dropdowns

* Add labels to fields

* Create wrapper for getting member by ID

* Add boolean selector

* Add number fields

* Add fields for basic string attributes

* Retrieve schema type from DB

* Move preprocessing to backend

* Fix enum type detection

* Remove duplicated code

* Fix attribute change error

* Run formatter

* Remove warnings

* Format client

* Populate edit fields from DB

* Add types to props

* Run formatter

* Remove alert

* Run formatter

* Get permissions from backend

* Disable input boxes if missing permissions

* Add enum dropdowns

* Format client

* Remove user ID override

* Change to ES6 defaults

* Remove unused package

* Change var to let

* Concisen member options endpoint

* Delete env file

* Unexport schema

* Use concise property iteration

* Make /options endpoint concise

* Remove unneeded exports

* Capitalize constant

* Shorten attribute change callback

* Run formatter

* Turn off default-props in linter

* Fix var name typo

* Change member page routing

* Run formatter

* Use useParams hook

* Change object syntax

* Run formatter

* Start creating tool to transfer data

* Consolidate envs and clean up app.js

* Fix yarn test not using .env

* Add lint-staged pre-commit hook (#27)

* Add lint-staged pre-commit hook

* Format "unstaged" files

* Sync prettier versions

* Format all files using new Prettier config

* Finish writing tool

* Format remaining fields

* Check for member uniqueness

* Fix enum formatting

* Run formatter

* Run formatter

* Run format with new hook

* Change new sign-in process to attempt to link user via email

* Show login error on frontend

* Remove unused Member page (renamed)

* Fix navbar welcome text spacing

* Fix lint

* Switch to cookie-session

* Change date attribute prop type to number

* Allow numbers for string attribute value

* Change enum attribute prop types

* Add keys to fields

* Only pass string to enum callback

* Fix default enum attribute option

* Rename StringAttribute to TextAttribute

Co-authored-by: ishaansharma <[email protected]>
Co-authored-by: Jeffrey Tang <[email protected]>
Co-authored-by: Yousef Ahmed <[email protected]>
  • Loading branch information
4 people authored Jan 18, 2021
1 parent a72be0b commit 711428d
Show file tree
Hide file tree
Showing 12 changed files with 136 additions and 96 deletions.
2 changes: 1 addition & 1 deletion api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
"test": "jest --setupFiles dotenv/config"
},
"dependencies": {
"cookie-session": "^1.4.0",
"cors": "^2.8.5",
"csvtojson": "^2.0.10",
"debug": "~2.6.9",
"dotenv": "^8.2.0",
"express": "~4.16.1",
"express-session": "^1.17.1",
"helmet": "^3.21.1",
"http-errors": "~1.6.3",
"if-env": "^1.0.4",
Expand Down
1 change: 0 additions & 1 deletion api/src/api/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ router.get(
const auth = passport.authenticate('google', {
successRedirect,
failureRedirect,
failureFlash: true,
});
auth(req, res, next);
},
Expand Down
18 changes: 9 additions & 9 deletions api/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const cors = require('cors');
const express = require('express');
const helmet = require('helmet');
const logger = require('morgan');
const session = require('express-session');
const cookieSession = require('cookie-session');
const bodyParser = require('body-parser');
const passport = require('passport');
const apiRoutes = require('./api');
Expand All @@ -24,14 +24,14 @@ app.use(bodyParser.json({ limit: '2.1mb' }));
app.use(bodyParser.urlencoded({ limit: '2.1mb', extended: false }));

// Session support, needed for authentication
app.use(
session({
secret: process.env.SESSION_SECRET,
cookie: {},
resave: false,
saveUninitialized: false,
}),
);
const sessionConfig = {
secret: process.env.SESSION_SECRET,
};
if (environment == 'production') {
app.set('trust proxy', 1);
sessionConfig.secure = true;
}
app.use(cookieSession(sessionConfig));

// Mongo setup
require('./utils/mongo-setup');
Expand Down
34 changes: 23 additions & 11 deletions api/src/utils/passport-setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ const GoogleStrategy = require('passport-google-oauth20').Strategy;
const passport = require('passport');
const Member = require('../models/member');

// Defines the default level a user gets assigned with upon first sign-in
const DEFAULT_LEVEL = process.env.DEFAULT_LEVEL || Member.levelEnum.TBD;

passport.serializeUser((user, done) => {
done(null, user._id);
});
Expand Down Expand Up @@ -33,17 +30,32 @@ passport.use(

if (user) {
// user exists
return cb(null, user);
cb(null, user);
} else {
const newUser = await new Member({
firstName: profile.name.givenName,
lastName: profile.name.familyName,
oauthID: profile.id,
// try to find a user with the same email
const unlinkedUser = await Member.findOne({
email: profile.emails[0].value,
level: DEFAULT_LEVEL,
}).save();
oauthID: null,
});

if (!unlinkedUser) {
// no unlinked user with matching email found
// don't link and reject authentication
cb(null, false);
} else {
// user with matching email found
// link user to oauthID and fill in name
unlinkedUser.oauthID = profile.id;
if (!unlinkedUser.firstName) {
unlinkedUser.firstName = profile.name.givenName;
}
if (!unlinkedUser.lastName) {
unlinkedUser.lastName = profile.name.familyName;
}
unlinkedUser.save();

cb(null, newUser);
cb(null, unlinkedUser);
}
}
},
),
Expand Down
4 changes: 2 additions & 2 deletions api/src/utils/user-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const getViewableFields = (currentUser, memberId) => {
const viewableFields = difference(allFields, neverViewableFields);
if (isDirector(currentUser)) {
return viewableFields;
} else if (currentUser._id == memberId) {
} else if (currentUser._id.toString() === memberId) {
return viewableFields;
} else {
return difference(viewableFields, nonViewableFields);
Expand All @@ -29,7 +29,7 @@ const getEditableFields = (currentUser, memberId) => {
const editableFields = difference(allFields, neverEditableFields);
if (isDirector(currentUser)) {
return editableFields;
} else if (currentUser._id == memberId) {
} else if (currentUser._id.toString() === memberId) {
return difference(editableFields, nonEditableFields);
} else {
return []; // Non-directors can never edit other users' info
Expand Down
67 changes: 30 additions & 37 deletions api/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1259,6 +1259,15 @@ convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
dependencies:
safe-buffer "~5.1.1"

cookie-session@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/cookie-session/-/cookie-session-1.4.0.tgz#c325aea685ceb9c8e4fd00b0313a46d547747380"
integrity sha512-0hhwD+BUIwMXQraiZP/J7VP2YFzqo6g4WqZlWHtEHQ22t0MeZZrNBSCxC1zcaLAs8ApT3BzAKizx9gW/AP9vNA==
dependencies:
cookies "0.8.0"
debug "2.6.9"
on-headers "~1.0.2"

[email protected]:
version "1.0.6"
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
Expand All @@ -1269,16 +1278,19 @@ [email protected]:
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=

[email protected]:
version "0.4.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==

cookiejar@^2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c"
integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==

[email protected]:
version "0.8.0"
resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.8.0.tgz#1293ce4b391740a8406e3c9870e828c4b54f3f90"
integrity sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==
dependencies:
depd "~2.0.0"
keygrip "~1.1.0"

copy-descriptor@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
Expand Down Expand Up @@ -1827,20 +1839,6 @@ expect@^25.5.0:
jest-message-util "^25.5.0"
jest-regex-util "^25.2.6"

express-session@^1.17.1:
version "1.17.1"
resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.17.1.tgz#36ecbc7034566d38c8509885c044d461c11bf357"
integrity sha512-UbHwgqjxQZJiWRTMyhvWGvjBQduGCSBDhhZXYenziMFjxst5rMV+aJZ6hKPHZnPyHGsrqRICxtX8jtEbm/z36Q==
dependencies:
cookie "0.4.0"
cookie-signature "1.0.6"
debug "2.6.9"
depd "~2.0.0"
on-headers "~1.0.2"
parseurl "~1.3.3"
safe-buffer "5.2.0"
uid-safe "~2.1.5"

express@~4.16.1:
version "4.16.4"
resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e"
Expand Down Expand Up @@ -3231,6 +3229,13 @@ [email protected]:
resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.2.tgz#78c4508894985b8d38a0dc15e1a8e11078f2ca93"
integrity sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ==

keygrip@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.1.0.tgz#871b1681d5e159c62a445b0c74b615e0917e7226"
integrity sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==
dependencies:
tsscmp "1.0.6"

keyv@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"
Expand Down Expand Up @@ -3862,7 +3867,7 @@ [email protected]:
resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2"
integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==

parseurl@~1.3.2, parseurl@~1.3.3:
parseurl@~1.3.2:
version "1.3.3"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
Expand Down Expand Up @@ -4082,11 +4087,6 @@ qs@^6.5.1:
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687"
integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==

random-bytes@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b"
integrity sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=

range-parser@~1.2.0:
version "1.2.1"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
Expand Down Expand Up @@ -4379,11 +4379,6 @@ [email protected], safe-buffer@~5.1.0, safe-buffer@~5.1.1:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==

[email protected]:
version "5.2.0"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==

[email protected], safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
Expand Down Expand Up @@ -5011,6 +5006,11 @@ tslib@^1.9.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==

[email protected]:
version "1.0.6"
resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb"
integrity sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==

tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
Expand Down Expand Up @@ -5065,13 +5065,6 @@ typedarray-to-buffer@^3.1.5:
dependencies:
is-typedarray "^1.0.0"

uid-safe@~2.1.5:
version "2.1.5"
resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.5.tgz#2b3d5c7240e8fc2e58f8aa269e5ee49c0857bd3a"
integrity sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==
dependencies:
random-bytes "~1.0.0"

[email protected]:
version "0.0.3"
resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.3.tgz#483126e11774df2f71b8b639dcd799c376162b82"
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/EditableAttribute/DateAttribute.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';

const DateAttribute = ({
value = '',
value = 0,
attributeLabel = '',
isDisabled = false,
onChange,
Expand All @@ -26,7 +26,7 @@ const DateAttribute = ({
};

DateAttribute.propTypes = {
value: PropTypes.string,
value: PropTypes.number,
attributeLabel: PropTypes.string,
isDisabled: PropTypes.bool,
onChange: PropTypes.func.isRequired,
Expand Down
25 changes: 18 additions & 7 deletions client/src/components/EditableAttribute/EnumAttribute.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,30 @@ import React from 'react';
import PropTypes from 'prop-types';
import Select from 'react-select';

const defaultDropdownOption = { label: '', value: '' };

const EnumAttribute = ({
value = '',
value = defaultDropdownOption.value,
valueOptions = [],
attributeLabel = '',
isDisabled = false,
onChange,
}) => {
const onValueChange = (option) => {
onChange(option, attributeLabel);
const onValueChange = (selectedOption) => {
onChange(selectedOption.value, attributeLabel);
};

const getOptionFromValue = (val) => {
const dropdownOption = valueOptions.find((option) => option.value === val);
if (dropdownOption) return dropdownOption;
return defaultDropdownOption;
};

return (
<div>
<p>{attributeLabel}</p>
<Select
defaultValue={value}
value={value}
placeholder={value}
value={getOptionFromValue(value)}
isDisabled={isDisabled}
name={attributeLabel}
options={valueOptions}
Expand All @@ -31,7 +37,12 @@ const EnumAttribute = ({

EnumAttribute.propTypes = {
value: PropTypes.string,
valueOptions: PropTypes.arrayOf(PropTypes.string),
valueOptions: PropTypes.arrayOf(
PropTypes.shape({
label: PropTypes.string,
value: PropTypes.string,
}),
),
attributeLabel: PropTypes.string,
isDisabled: PropTypes.bool,
onChange: PropTypes.func.isRequired,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { TextField } from '@hack4impact-uiuc/bridge';

const StringAttribute = ({
const TextAttribute = ({
type = 'text',
value = '',
attributeLabel = '',
Expand All @@ -26,12 +26,12 @@ const StringAttribute = ({
);
};

StringAttribute.propTypes = {
TextAttribute.propTypes = {
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
type: PropTypes.string,
value: PropTypes.string,
attributeLabel: PropTypes.string,
isDisabled: PropTypes.bool,
onChange: PropTypes.func.isRequired,
};

export default StringAttribute;
export default TextAttribute;
5 changes: 1 addition & 4 deletions client/src/components/navbar/Navbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@ const Navbar = ({ user }) => (
</Link>
</h2>
<div className="profile-item">
<h2 id="welcome-text">
Hello,
{user.firstName}!
</h2>
<h2 id="welcome-text">Hello, {user.firstName}!</h2>
<Profile user={user} />
</div>
</nav>
Expand Down
Loading

1 comment on commit 711428d

@vercel
Copy link

@vercel vercel bot commented on 711428d Jan 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.