Skip to content

Commit c3b1d47

Browse files
committed
Merge branch 'master' into nginx_setup
# Conflicts: # src/docker-compose.yml # src/server/Dockerfile # src/server/app.py
2 parents a237022 + d6d9e64 commit c3b1d47

30 files changed

+1125
-63
lines changed

src/client/src/pages/DataView360/DataView360.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,8 @@ class DataView360 extends Component {
124124
<TableBody>
125125
{
126126
_.map(participantListGrouped, (row_group, index) => {
127-
return _.map(row_group, row => {
128-
return <TableRow key={row.source_id}
127+
return _.map(row_group, (row, idx) => {
128+
return <TableRow key={`${row.source_id}${idx}`}
129129
className={tableRowColors[index % _.size(tableRowColors)]}
130130
onClick={() => this.handleGetParticipant(row.matching_id)}>
131131
<TableCell align="left">{row.matching_id}</TableCell>
@@ -185,19 +185,19 @@ class DataView360 extends Component {
185185
this.state.showParticipant === true) && (
186186
<Paper className={styles.main} elevation={1} style={{"padding": "1em"}}>
187187
<ContactInfo participant={_.get(this.state, 'participantData.contact_details')}/>
188-
<Container>
189-
<Grid container direction="row" justify="center" alignItems="center" style={{"margin-top": "1em"}}>
190-
<Button variant="contained" color="primary"
191-
onClick={() => {
192-
this.setState({showParticipant: false, showTable: true, showSearchBar: true })
193-
}}>Back to Results
194-
</Button>
188+
<Grid container direction="row" justify="center">
189+
<Grid item style={{"marginTop": "1em", "position": "fixed"}}>
190+
<Button variant="contained" color="primary"
191+
onClick={() => {
192+
this.setState({showParticipant: false, showTable: true, showSearchBar: true })
193+
}}>Back to Results
194+
</Button>
195+
</Grid>
195196
</Grid>
196-
</Container>
197197
<Donations donations={_.get(this.state, 'participantData.donations')}/>
198198
<Adoptions adoptions={_.get(this.state, 'participantData.adoptions')}/>
199199
<Volunteer volunteer={_.get(this.state, 'participantData.shifts')}
200-
volunteerShifts={_.get(this.state, 'participantData.volgistics_shifts_results')}/>
200+
volunteerShifts={_.get(this.state, 'participantData.shifts')}/>
201201

202202
</Paper>)}
203203
{this.state.isDataBusy === true && (

src/client/src/pages/DataView360/components/Adoptions.js

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,36 @@ class Adoptions extends Component {
4141
render() {
4242
// todo: update when we add pet info
4343
// todo: clean array of animal_id
44+
const numAdoptions = _.size(this.props.adoptions);
4445
return (<Container className={styles.adoptions} style={{"marginTop":"1em"}}>
45-
<Typography className={styles.adoptions_title} variant='h4'>Adoption/Foster Records (Top 3)</Typography>
46+
<Typography className={styles.adoptions_title} variant='h4'>Adoption/Foster Records {(numAdoptions > 3) && "(Showing latest 3 out of " + numAdoptions + ")"}</Typography>
4647
<TableContainer className="main_table_container" style={{"marginTop":"1em"}} component={Paper} variant='outlined'>
4748
<Table className="main_table">
4849
<TableHead>
4950
<TableRow>
50-
<StyledTableCell align="center">Number of Adoptions</StyledTableCell>
51+
<StyledTableCell align="center">Name</StyledTableCell>
52+
<StyledTableCell align="center">Adoption Type</StyledTableCell>
53+
<StyledTableCell align="center">Adoption Subtype</StyledTableCell>
54+
<StyledTableCell align="center">Animal Type</StyledTableCell>
55+
<StyledTableCell align="center">Breed</StyledTableCell>
56+
<StyledTableCell align="center">Age</StyledTableCell>
57+
<StyledTableCell align="center">Photo</StyledTableCell>
5158
</TableRow>
5259
</TableHead>
5360
<TableBody>
54-
<StyledTableRow>
55-
<TableCell align="center"> {_.size(this.getAnimalIds())}</TableCell>
61+
{_.map(this.props.adoptions, (adoptionInfo, index) => {
62+
const photoLink = adoptionInfo["animal_details"]["Photos"][0]
63+
const photo = <img src={photoLink} style={{"maxWidth": "100px"}}/>;
64+
return <StyledTableRow key={adoptionInfo["Time"] + index}>
65+
<TableCell align="center">{adoptionInfo["animal_details"]["Name"]}</TableCell>
66+
<TableCell align="center">{adoptionInfo["Type"]}</TableCell>
67+
<TableCell align="center">{adoptionInfo["Subtype"]}</TableCell>
68+
<TableCell align="center">{adoptionInfo["animal_details"]["Type"]}</TableCell>
69+
<TableCell align="center">{adoptionInfo["animal_details"]["Breed"]}</TableCell>
70+
<TableCell align="center">{(parseInt(adoptionInfo["animal_details"]["Age"])/12).toFixed(2)}</TableCell>
71+
<TableCell align="center">{photo}</TableCell>
5672
</StyledTableRow>
73+
})}
5774
</TableBody>
5875
</Table>
5976
</TableContainer>

src/client/src/pages/DataView360/components/ContactInfo.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,19 @@ const StyledContact = withStyles((theme)=>({
1616

1717
class ContactInfo extends Component {
1818
render() {
19-
const participantArray = _.get(this.props, "participant")
20-
const participant = participantArray[0]
19+
// TODO: move to the backend
20+
let participantArray = _.get(this.props, "participant");
21+
let participant = {};
22+
if (participantArray.length === 1) {
23+
participant = participantArray[0];
24+
} else {
25+
participantArray = _.filter(participantArray, function(p) {
26+
if (p["source_type"] === "salesforcecontacts") {
27+
return p;
28+
}
29+
});
30+
participant = participantArray[0];
31+
}
2132
const phoneStr = participant.mobile;
2233
let phone = _.isEmpty(phoneStr) ? '-' : phoneStr.split(" ").join("");
2334
return (<Container className={styles.contact_info}>

src/docker-compose.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ services:
1010
- postgres:/var/lib/postgresql/data
1111
environment:
1212
POSTGRES_PASSWORD: thispasswordisverysecure
13+
POSTGRES_DB: paws
1314

1415
server:
1516
container_name: paws-compose-server
@@ -20,6 +21,7 @@ services:
2021
- db
2122
volumes:
2223
- src_archive:/app/static/raw_data
24+
2325
environment:
2426
- FLASK_ENV=development
2527

@@ -35,8 +37,12 @@ services:
3537
- PAWS_API_HOST=paws-compose-server
3638
stdin_open: true
3739

40+
3841
#using named volumes fixs a windows docker bug relating to container permissions
3942
#https://stackoverflow.com/questions/49148754/docker-container-shuts-down-giving-data-directory-has-wrong-ownership-error-wh
4043
volumes:
4144
postgres:
42-
src_archive:
45+
src_archive:
46+
47+
48+

src/server/Dockerfile

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
FROM python:3.8
22

3+
RUN apt-get update && apt-get install -y vim
4+
35
WORKDIR /app
46

57
ENV PYTHONDONTWRITEBYTECODE 1
@@ -39,6 +41,15 @@ RUN chmod 777 /paws-data-pipeline/server
3941
# RUN ufw allow 5000
4042
WORKDIR /app
4143

42-
# CMD python app.py
4344
# --uid uwsgi
44-
CMD uwsgi --http-socket :5000 --plugin python38 --module wsgi:app --chdir /app --pythonpath .
45+
CMD uwsgi --http-socket :5000 --plugin python38 --module wsgi:app --chdir /app --pythonpath .
46+
# we may want to switch this to a script which logs output, etc?
47+
48+
RUN set FLASK_APP=server/app.py
49+
RUN export FLASK_APP
50+
51+
# This abomination ensures that the PG server has finished its restart cycle
52+
CMD echo "SLEEPING 10"; sleep 10; echo "WAKING"; alembic upgrade head ; python -m flask run --host=0.0.0.0 --no-reload
53+
54+
# --no-reload prevents Flask restart, which usually happens in middle of create_base_users()
55+
#TODO: SECURITY - ensure we are not running in debug mode in production

src/server/alembic.ini

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# A generic, single database configuration.
2+
3+
[alembic]
4+
# path to migration scripts
5+
script_location = alembic
6+
7+
# template used to generate migration files
8+
# file_template = %%(rev)s_%%(slug)s
9+
10+
# timezone to use when rendering the date
11+
# within the migration file as well as the filename.
12+
# string value is passed to dateutil.tz.gettz()
13+
# leave blank for localtime
14+
# timezone =
15+
16+
# max length of characters to apply to the
17+
# "slug" field
18+
# truncate_slug_length = 40
19+
20+
# set to 'true' to run the environment during
21+
# the 'revision' command, regardless of autogenerate
22+
# revision_environment = false
23+
24+
# set to 'true' to allow .pyc and .pyo files without
25+
# a source .py file to be detected as revisions in the
26+
# versions/ directory
27+
# sourceless = false
28+
29+
# version location specification; this defaults
30+
# to alembic/versions. When using multiple version
31+
# directories, initial revisions must be specified with --version-path
32+
# version_locations = %(here)s/bar %(here)s/bat alembic/versions
33+
34+
# the output encoding used when revision files
35+
# are written from script.py.mako
36+
# output_encoding = utf-8
37+
38+
# Container
39+
sqlalchemy.url = postgresql://postgres:thispasswordisverysecure@paws-compose-db/paws
40+
41+
# Local
42+
# sqlalchemy.url = postgresql://postgres:thispasswordisverysecure@localhost/paws
43+
44+
45+
[post_write_hooks]
46+
# post_write_hooks defines scripts or Python functions that are run
47+
# on newly generated revision scripts. See the documentation for further
48+
# detail and examples
49+
50+
# format using "black" - use the console_scripts runner, against the "black" entrypoint
51+
# hooks=black
52+
# black.type=console_scripts
53+
# black.entrypoint=black
54+
# black.options=-l 79
55+
56+
# Logging configuration
57+
[loggers]
58+
keys = root,sqlalchemy,alembic
59+
60+
[handlers]
61+
keys = console
62+
63+
[formatters]
64+
keys = generic
65+
66+
[logger_root]
67+
level = WARN
68+
handlers = console
69+
qualname =
70+
71+
[logger_sqlalchemy]
72+
level = WARN
73+
handlers =
74+
qualname = sqlalchemy.engine
75+
76+
[logger_alembic]
77+
level = INFO
78+
handlers =
79+
qualname = alembic
80+
81+
[handler_console]
82+
class = StreamHandler
83+
args = (sys.stderr,)
84+
level = NOTSET
85+
formatter = generic
86+
87+
[formatter_generic]
88+
format = %(levelname)-5.5s [%(name)s] %(message)s
89+
datefmt = %H:%M:%S

src/server/alembic/README

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Generic single-database configuration.

src/server/alembic/env.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
from logging.config import fileConfig
2+
3+
from sqlalchemy import engine_from_config
4+
from sqlalchemy import pool
5+
6+
from alembic import context
7+
8+
# this is the Alembic Config object, which provides
9+
# access to the values within the .ini file in use.
10+
config = context.config
11+
12+
# Interpret the config file for Python logging.
13+
# This line sets up loggers basically.
14+
fileConfig(config.config_file_name)
15+
16+
# add your model's MetaData object here
17+
# for 'autogenerate' support
18+
# from myapp import mymodel
19+
# target_metadata = mymodel.Base.metadata
20+
target_metadata = None
21+
22+
# other values from the config, defined by the needs of env.py,
23+
# can be acquired:
24+
# my_important_option = config.get_main_option("my_important_option")
25+
# ... etc.
26+
27+
28+
def run_migrations_offline():
29+
"""Run migrations in 'offline' mode.
30+
31+
This configures the context with just a URL
32+
and not an Engine, though an Engine is acceptable
33+
here as well. By skipping the Engine creation
34+
we don't even need a DBAPI to be available.
35+
36+
Calls to context.execute() here emit the given string to the
37+
script output.
38+
39+
"""
40+
url = config.get_main_option("sqlalchemy.url")
41+
context.configure(
42+
url=url,
43+
target_metadata=target_metadata,
44+
literal_binds=True,
45+
dialect_opts={"paramstyle": "named"},
46+
)
47+
48+
with context.begin_transaction():
49+
context.run_migrations()
50+
51+
52+
def run_migrations_online():
53+
"""Run migrations in 'online' mode.
54+
55+
In this scenario we need to create an Engine
56+
and associate a connection with the context.
57+
58+
"""
59+
connectable = engine_from_config(
60+
config.get_section(config.config_ini_section),
61+
prefix="sqlalchemy.",
62+
poolclass=pool.NullPool,
63+
)
64+
65+
with connectable.connect() as connection:
66+
context.configure(
67+
connection=connection, target_metadata=target_metadata
68+
)
69+
70+
with context.begin_transaction():
71+
context.run_migrations()
72+
73+
74+
if context.is_offline_mode():
75+
run_migrations_offline()
76+
else:
77+
run_migrations_online()

src/server/alembic/script.py.mako

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""${message}
2+
3+
Revision ID: ${up_revision}
4+
Revises: ${down_revision | comma,n}
5+
Create Date: ${create_date}
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
${imports if imports else ""}
11+
12+
# revision identifiers, used by Alembic.
13+
revision = ${repr(up_revision)}
14+
down_revision = ${repr(down_revision)}
15+
branch_labels = ${repr(branch_labels)}
16+
depends_on = ${repr(depends_on)}
17+
18+
19+
def upgrade():
20+
${upgrades if upgrades else "pass"}
21+
22+
23+
def downgrade():
24+
${downgrades if downgrades else "pass"}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""Add pdp_users full_name
2+
3+
Revision ID: 36c4ecbfd11a
4+
Revises: 7138d52f92d6
5+
Create Date: 2020-12-18 15:28:17.367718
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
11+
12+
# revision identifiers, used by Alembic.
13+
revision = "36c4ecbfd11a"
14+
down_revision = "7138d52f92d6"
15+
branch_labels = None
16+
depends_on = None
17+
18+
19+
def upgrade():
20+
op.add_column("pdp_users", sa.Column("full_name", sa.String))
21+
22+
23+
def downgrade():
24+
pass

0 commit comments

Comments
 (0)