Add Protogarden image to Home stats
This commit is contained in:
parent
152107a9bb
commit
adb14f5c4f
|
@ -192,6 +192,42 @@ def process_image_upload(upload, crop):
|
||||||
return small, medium, large
|
return small, medium, large
|
||||||
|
|
||||||
|
|
||||||
|
GARDEN_MEDIUM_SIZE = 500
|
||||||
|
|
||||||
|
def process_garden_image(upload):
|
||||||
|
try:
|
||||||
|
pic = Image.open(upload)
|
||||||
|
except OSError:
|
||||||
|
raise serializers.ValidationError(dict(non_field_errors='Invalid image file.'))
|
||||||
|
|
||||||
|
logging.debug('Detected format: %s', pic.format)
|
||||||
|
|
||||||
|
if pic.format == 'PNG':
|
||||||
|
ext = '.png'
|
||||||
|
elif pic.format == 'JPEG':
|
||||||
|
ext = '.jpg'
|
||||||
|
else:
|
||||||
|
raise serializers.ValidationError(dict(non_field_errors='Image must be a jpg or png.'))
|
||||||
|
|
||||||
|
pic = ImageOps.exif_transpose(pic)
|
||||||
|
|
||||||
|
draw = ImageDraw.Draw(pic)
|
||||||
|
|
||||||
|
timestamp = now_alberta_tz().strftime('%a %b %-d, %Y %-I:%M %p')
|
||||||
|
|
||||||
|
font = ImageFont.truetype('DejaVuSans.ttf', 60)
|
||||||
|
draw.text((10, 10), timestamp, (0,0,0), font=font)
|
||||||
|
|
||||||
|
large = 'garden-large' + ext
|
||||||
|
pic.save(STATIC_FOLDER + large)
|
||||||
|
|
||||||
|
medium = 'garden-medium' + ext
|
||||||
|
pic.thumbnail([GARDEN_MEDIUM_SIZE, GARDEN_MEDIUM_SIZE], Image.ANTIALIAS)
|
||||||
|
pic.save(STATIC_FOLDER + medium)
|
||||||
|
|
||||||
|
return medium, large
|
||||||
|
|
||||||
|
|
||||||
CARD_TEMPLATE_FILE = 'misc/member_card_template.jpg'
|
CARD_TEMPLATE_FILE = 'misc/member_card_template.jpg'
|
||||||
CARD_PHOTO_SIZE = 425
|
CARD_PHOTO_SIZE = 425
|
||||||
CARD_PHOTO_MARGIN_TOP = 75
|
CARD_PHOTO_MARGIN_TOP = 75
|
||||||
|
|
|
@ -857,7 +857,6 @@ class StatsViewSet(viewsets.ViewSet, List):
|
||||||
month_total=month_total,
|
month_total=month_total,
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
@action(detail=False, methods=['post'])
|
@action(detail=False, methods=['post'])
|
||||||
def autoscan(self, request):
|
def autoscan(self, request):
|
||||||
if 'autoscan' not in request.data:
|
if 'autoscan' not in request.data:
|
||||||
|
@ -866,6 +865,18 @@ class StatsViewSet(viewsets.ViewSet, List):
|
||||||
cache.set('autoscan', request.data['autoscan'])
|
cache.set('autoscan', request.data['autoscan'])
|
||||||
return Response(200)
|
return Response(200)
|
||||||
|
|
||||||
|
@action(detail=False, methods=['post'])
|
||||||
|
def garden(self, request):
|
||||||
|
if 'photo' not in request.data:
|
||||||
|
raise exceptions.ValidationError(dict(photo='This field is required.'))
|
||||||
|
|
||||||
|
photo = request.data['photo']
|
||||||
|
medium, large = utils.process_garden_image(photo)
|
||||||
|
|
||||||
|
logging.debug('Wrote garden images to %s and %s', medium, large)
|
||||||
|
|
||||||
|
return Response(200)
|
||||||
|
|
||||||
|
|
||||||
class MemberCountViewSet(Base, List):
|
class MemberCountViewSet(Base, List):
|
||||||
pagination_class = None
|
pagination_class = None
|
||||||
|
|
|
@ -27,6 +27,7 @@ import { Subscribe } from './PayPal.js';
|
||||||
import { PasswordReset, ConfirmReset } from './PasswordReset.js';
|
import { PasswordReset, ConfirmReset } from './PasswordReset.js';
|
||||||
import { NotFound, PleaseLogin } from './Misc.js';
|
import { NotFound, PleaseLogin } from './Misc.js';
|
||||||
import { Debug } from './Debug.js';
|
import { Debug } from './Debug.js';
|
||||||
|
import { Garden } from './Garden.js';
|
||||||
import { Footer } from './Footer.js';
|
import { Footer } from './Footer.js';
|
||||||
|
|
||||||
const APP_VERSION = 3; // TODO: automate this
|
const APP_VERSION = 3; // TODO: automate this
|
||||||
|
@ -263,6 +264,10 @@ function App() {
|
||||||
<Classes token={token} user={user} refreshUser={refreshUser} />
|
<Classes token={token} user={user} refreshUser={refreshUser} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
|
<Route path='/garden'>
|
||||||
|
<Garden />
|
||||||
|
</Route>
|
||||||
|
|
||||||
{user && user.member.set_details ?
|
{user && user.member.set_details ?
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path='/account'>
|
<Route path='/account'>
|
||||||
|
|
15
webclient/src/Garden.js
Normal file
15
webclient/src/Garden.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import React, { useState, useEffect, useReducer, useContext } from 'react';
|
||||||
|
import { BrowserRouter as Router, Switch, Route, Link, useParams, useHistory } from 'react-router-dom';
|
||||||
|
import { Button, Container, Checkbox, Dimmer, Divider, Dropdown, Form, Grid, Header, Icon, Image, Menu, Message, Segment, Table } from 'semantic-ui-react';
|
||||||
|
import { apiUrl, statusColor, BasicTable, staticUrl, requester } from './utils.js';
|
||||||
|
import { NotFound } from './Misc.js';
|
||||||
|
|
||||||
|
export function Garden(props) {
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<Header size='large'>Protogarden</Header>
|
||||||
|
|
||||||
|
<Image src={staticUrl + '/garden-large.jpg'} />
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
|
@ -351,6 +351,12 @@ export function Home(props) {
|
||||||
|
|
||||||
<SignForm token={token} />
|
<SignForm token={token} />
|
||||||
|
|
||||||
|
<p>Protogarden:</p>
|
||||||
|
|
||||||
|
<Link to='/garden'>
|
||||||
|
<Image src={staticUrl + '/garden-medium.jpg'} />
|
||||||
|
</Link>
|
||||||
|
|
||||||
</Segment>
|
</Segment>
|
||||||
}
|
}
|
||||||
</Grid.Column>
|
</Grid.Column>
|
||||||
|
|
|
@ -36,16 +36,18 @@ export function SignForm(props) {
|
||||||
<Form onSubmit={handleSubmit}>
|
<Form onSubmit={handleSubmit}>
|
||||||
<p>Send a message to the sign:</p>
|
<p>Send a message to the sign:</p>
|
||||||
|
|
||||||
<Form.Input
|
<Form.Group>
|
||||||
name='sign'
|
<Form.Input
|
||||||
onChange={handleChange}
|
name='sign'
|
||||||
value={sign}
|
onChange={handleChange}
|
||||||
error={error.sign}
|
value={sign}
|
||||||
/>
|
error={error.sign}
|
||||||
|
/>
|
||||||
|
|
||||||
<Form.Button loading={loading} error={error.non_field_errors}>
|
<Form.Button loading={loading} error={error.non_field_errors}>
|
||||||
Submit
|
Submit
|
||||||
</Form.Button>
|
</Form.Button>
|
||||||
|
</Form.Group>
|
||||||
{success && <div>Success!</div>}
|
{success && <div>Success!</div>}
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user