Skip to content

Commit

Permalink
Merge branch 'master' of github.com:maplethorpej/packstack
Browse files Browse the repository at this point in the history
� Conflicts:
�	frontend/src/app/components/FormFields/styles.ts
  • Loading branch information
maplethorpej committed Feb 13, 2021
2 parents b2714c7 + 46e32a5 commit 156e803
Show file tree
Hide file tree
Showing 31 changed files with 352 additions and 57 deletions.
69 changes: 66 additions & 3 deletions api/controllers/pack.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import Sequelize from 'sequelize';
let router = express.Router();

import models from '../models';
import { authenticate } from "../utils/jwt";
import { authenticate, authenicatePublicRequest } from "../utils/jwt";
import { csvItems, packItemPayload, packPayload } from "../utils/build-payload";

// Get
router.get('/:id', async (req, res) => {
router.get('/:id', authenicatePublicRequest, async (req, res) => {
let { id } = req.params;
models.Pack.findOne({
where: { id },
Expand All @@ -21,7 +21,17 @@ router.get('/:id', async (req, res) => {
{ model: models.User, attributes: ['id', 'username'] },
]
})
.then(pack => res.json(pack))
.then(pack => {
if (pack.public) {
res.json(pack);
} else { //when the pack is private, only allow the owner of the pack to view
if (req.user && pack.userId == req.user.id) {
res.json(pack);
} else {
res.sendStatus(403); //return 'forbidden'
}
}
})
.catch(err => res.json(err));
});

Expand Down Expand Up @@ -177,4 +187,57 @@ router.post('/remove-item', authenticate, (req, res) => {

});

// make a copy of a pack and its items
router.post('/copy-pack', authenticate, (req, res) => {
const { packId } = req.body;

// verify ownership
if (packId) {
models.Pack.findOne({ where: { id: packId, userId: req.user.id } })
.then(pack => {
if (!pack) {
return res.sendStatus(401);
}
else { //owner of pack is making request
models.Pack.findOne({
where: { id: packId },
include: [
{
model: models.Item, through: { where: { packId: packId } }, include: [
{ model: models.Category, as: 'Category', attributes: ['name'] }
]
},
]
})
.then(pack => {
models.Pack.create({ ...pack, userId: req.user.id, title: "Copy of " + pack.title })
.then(newPack => {
//associate items by id
const assocItems = pack.items.map(item => ({
...item.packItem,
quantity: item.packItem.quantity || 1,
packId: newPack.id,
itemId: item.id
}));
models.PackItem.bulkCreate(assocItems)
.then(() => {
// retrieve new pack w/ items
models.Pack.findOne({
where: { id: newPack.id },
include: { model: models.Item, through: { where: { packId: newPack.id } } }
})
.then(pack => res.json(pack))
.catch(err => res.json(err));
})
.catch(err => res.status(400).json(err))
})
.catch(err => res.status(400).json(err))
})
.catch(err => res.json(err));
}
})
.catch(err => res.status(400).json(err));
}
});

module.exports = router;
15 changes: 15 additions & 0 deletions api/migrations/20210103153722-add-item-notes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use strict';

module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.addColumn('items', 'notes', {
type: Sequelize.STRING(500),
defaultValue: ''
}
})
},

down: (queryInterface, Sequelize) => {
return queryInterface.removeColumn('items', 'notes'),
}
};
5 changes: 4 additions & 1 deletion api/models/item.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ const item = (sequelize, DataTypes) => {
allowNull: false,
defaultValue: false
},
notes: {
type: DataTypes.STRING(500)
},
});

Item.associate = models => {
Expand All @@ -88,4 +91,4 @@ const item = (sequelize, DataTypes) => {
return Item;
};

export default item;
export default item;
3 changes: 3 additions & 0 deletions api/models/pack.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ const pack = (sequelize, DataTypes) => {
},
gender: {
type: DataTypes.ENUM(Object.values(gender))
},
userId: {
type: DataTypes.INTEGER
}
});

Expand Down
24 changes: 23 additions & 1 deletion api/utils/jwt.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,26 @@ export const authenticate = (req, res, next) => {
next();
})
.catch(() => res.sendStatus(400));
};
};

/*
This method will authenticate the user if one is logged in, but does not return a 400/401
if there the user is not logged in to allow for public viewing of packs.
This could also be used for public/private profiles.
*/
export const authenicatePublicRequest = (req, res, next) => {
const authHeader = req.get('authorization');
if (!authHeader) {
req.user = undefined;
next();
} else {
const token = authHeader.split(' ')[1];
const decoded = jwt.verify(token, process.env.JWT_SECRET);
models.User.findOne({where: {id: decoded.id}})
.then(user => {
req.user = user;
next();
})
.catch(() => res.sendStatus(400));
}
}
12 changes: 6 additions & 6 deletions api/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -991,9 +991,9 @@ inherits@2.0.3:
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=

ini@^1.3.4:
version "1.3.5"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
version "1.3.8"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==

ip@^1.1.4, ip@^1.1.5:
version "1.1.5"
Expand Down Expand Up @@ -1180,9 +1180,9 @@ lodash.once@^4.0.0:
integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=

lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.5:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
version "4.17.19"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==

lru-cache@^4.1.2, lru-cache@^4.1.5:
version "4.1.5"
Expand Down
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"react-ga": "^2.5.6",
"react-linkify": "^1.0.0-alpha",
"react-router-dom": "^5.0.1",
"react-router-navigation-confirm": "^1.1.7",
"react-select": "^3.1.0",
"recharts": "^1.7.1",
"resolve": "1.10.0",
Expand Down
20 changes: 15 additions & 5 deletions frontend/src/app/Inventory/Item.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import { isEqual } from 'lodash';
import { Icon, Tooltip } from 'antd';

import { Item as ItemType } from "types/item";
import { Update } from "types/api/item";
Expand All @@ -8,11 +9,12 @@ import { AppContext } from "AppContext";
import { Input, Option, SelectCreatable, Select } from "app/components/FormFields";
import { alertSuccess, alertWarn } from "app/components/Notifications";
import EditItem from "app/components/EditItem";
import { DotIcon } from "app/components/Icons";

import { categoryOptions, weightUnitOptions } from "lib/utils/form";
import { categorySelectValue } from "lib/utils/categories";

import { Grid, PairGrid, inlineStyles } from "styles/grid";
import { Grid, PairGrid, NotesIndicator, inlineStyles } from "styles/grid";

interface ItemProps {
item: ItemType;
Expand Down Expand Up @@ -55,24 +57,32 @@ const Item: React.FC<ItemProps> = ({item, updateItem, fetchItems}) => {
.catch(() => alertWarn({message: 'Error updating item.'}));
}


const categoryValue = categorySelectValue(app.categories, copy.categoryId);
const {product_name, name, weight_unit, weight, price} = copy;
const {product_name, name, weight_unit, weight, price, notes} = copy;
const hasNotes = notes !== "";
return (
<>
<Grid>
<div className="align-center">
<NotesIndicator className={hasNotes ? 'active' : ''}>
<Tooltip title={hasNotes ? notes : "No notes on this item"}
mouseEnterDelay={.1} placement="right">
<Icon component={DotIcon}/>
</Tooltip>
</NotesIndicator>
</div>
<div>
<Input value={name || ''}
onChange={v => update('name', v)}
onBlur={handleSave}
style={inlineStyles}/>
</div>
<div>
<Input value={product_name || ''}
placeholder="product name"
onChange={v => update('product_name', v)}
onBlur={handleSave}
style={inlineStyles}/>
</div>
<div>
<SelectCreatable
options={categoryOptions(app.categories)}
Expand Down Expand Up @@ -130,4 +140,4 @@ const Item: React.FC<ItemProps> = ({item, updateItem, fetchItems}) => {
)
};

export default React.memo(Item);
export default React.memo(Item);
17 changes: 15 additions & 2 deletions frontend/src/app/Pack/Pack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ import Items from './Items';
import { getWeightByCategory } from 'lib/utils/weight';

import { Credit, PackWrapper, SectionHeader, SectionTitle, TripDescription } from "./styles";
import FullPageError from 'app/components/FullPageError';

const Pack: React.FC<PackSpecs.Props> = ({ getPack, weightUnit, packId }) => {
const [loading, setLoading] = React.useState<boolean>(true);
const [packForbidden, setPackForbidden] = React.useState<boolean>(true);
const [pack, setPack] = React.useState<PackType | null>(null);
const [unit, setUnit] = React.useState<WeightUnit>(weightUnit);
const { dispatch } = useSidebar();
Expand All @@ -34,9 +36,16 @@ const Pack: React.FC<PackSpecs.Props> = ({ getPack, weightUnit, packId }) => {
.then(pack => {
setPack(pack);
setLoading(false);
setPackForbidden(false);
})
.catch(() => {
alertError({ message: 'Unable to retrieve pack.' });
.catch(e => {
setLoading(false);
if (e.message.includes("failed with status code 403")){//when forbidden to view
setPackForbidden(true);
}
else {
alertError({ message: 'Unable to retrieve pack.' });
}
});

return function cleanup() {
Expand Down Expand Up @@ -68,6 +77,10 @@ const Pack: React.FC<PackSpecs.Props> = ({ getPack, weightUnit, packId }) => {
if (loading) {
return <Loading size="large"/>
}

if (packForbidden) {
return <FullPageError text="This pack is private. If you're sure this is your pack, make sure you're logged in."></FullPageError>
}

if (!pack) {
return <p>Pack not found!</p>
Expand Down
Loading

0 comments on commit 156e803

Please sign in to comment.