Skip to content

Commit 977d9bf

Browse files
gupta-utkarshdeshraj
authored andcommitted
Add demo embedding and addition of logs (Cloud-CV#26)
1 parent 71c7f99 commit 977d9bf

File tree

20 files changed

+357
-34
lines changed

20 files changed

+357
-34
lines changed

apps/demos/views.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
@permission_classes((permissions.AllowAny,))
1313
def get_demos(request):
1414
"""
15-
Get a list of team members
15+
Get a list of demos
1616
"""
1717
demos = Demo.objects.filter(is_disabled=False).order_by('title')
1818
serializer = DemoSerializer(demos, many=True, context={'request': request})
@@ -25,7 +25,7 @@ def get_demos(request):
2525
@permission_classes((permissions.AllowAny,))
2626
def get_projects(request):
2727
"""
28-
Get a list of team members
28+
Get a list of projects
2929
"""
3030
projects = Project.objects.filter(is_visible=True).order_by('title')
3131
serializer = ProjectSerializer(projects, many=True, context={'request': request})

apps/logs/urls.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from django.conf.urls import url
2+
3+
from .import views
4+
5+
6+
urlpatterns = [
7+
url(r'^(?P<demo_permalink>[A-Za-z]+)/add/$', views.post_log, name='post_log'),
8+
url(r'^(?P<log_id>[0-9]+)/output/$', views.post_output, name='post_output'),
9+
]

apps/logs/views.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import logging
2+
from rest_framework import permissions, status
3+
from rest_framework.decorators import (api_view, permission_classes, throttle_classes,)
4+
from rest_framework.response import Response
5+
from rest_framework.throttling import AnonRateThrottle
6+
from base64 import b64decode
7+
from django.core.files.base import ContentFile
8+
9+
from demos.models import Demo
10+
from .models import DemoLog, LogImage, LogText
11+
12+
13+
@throttle_classes([AnonRateThrottle, ])
14+
@api_view(['POST'])
15+
@permission_classes((permissions.AllowAny,))
16+
def post_log(request, demo_permalink):
17+
"""
18+
Create and save a log
19+
"""
20+
demo = Demo.objects.get(permalink=demo_permalink)
21+
if not demo:
22+
error_message = {'error': 'Demo not found!'}
23+
return Response(error_message, status=status.HTTP_404_NOT_FOUND)
24+
25+
try:
26+
demo_log = DemoLog.objects.create(
27+
demo=demo,
28+
log_type='Submission'
29+
)
30+
except Exception:
31+
error_message = {'error': 'Demo log could not be created'}
32+
return Response(error_message, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
33+
34+
i = 0
35+
try:
36+
while True:
37+
textdata = request.data['input-text-{}'.format(i)]
38+
LogText.objects.create(
39+
demo_log=demo_log,
40+
text=textdata,
41+
text_type='Input'
42+
)
43+
i += 1
44+
except Exception:
45+
logging.exception('Key not found while saving input')
46+
pass
47+
48+
imagedata = []
49+
i = 0
50+
try:
51+
while True:
52+
imagedata = request.FILES['input-image-{}'.format(i)]
53+
LogImage.objects.create(
54+
demo_log=demo_log,
55+
image=imagedata,
56+
image_type='Input'
57+
)
58+
i += 1
59+
except Exception:
60+
logging.exception('Key not found while saving output')
61+
pass
62+
63+
success_message = {'success': {'id': demo_log.id}}
64+
return Response(success_message, status=status.HTTP_200_OK)
65+
66+
67+
@throttle_classes([AnonRateThrottle, ])
68+
@api_view(['POST'])
69+
@permission_classes((permissions.AllowAny,))
70+
def post_output(request, log_id):
71+
"""
72+
Get a list of projects
73+
"""
74+
demo_log = DemoLog.objects.get(id=log_id)
75+
if not demo_log:
76+
error_message = {'error': 'Demo log not found!'}
77+
return Response(error_message, status=status.HTTP_404_NOT_FOUND)
78+
79+
count_image_inputs = demo_log.demo.image_inputs
80+
count_text_inputs = demo_log.demo.text_inputs
81+
82+
if count_image_inputs > 0 and count_text_inputs == 0:
83+
for image in request.data:
84+
image = str(image).split(",")[1]
85+
missing_padding = len(image) % 4
86+
if missing_padding != 0:
87+
image += b'=' * (4 - missing_padding)
88+
image_data = b64decode(image)
89+
LogImage.objects.create(
90+
demo_log=demo_log,
91+
image=ContentFile(image_data, 'whatup.png'),
92+
image_type='Output'
93+
)
94+
elif count_text_inputs > 0 and count_image_inputs == 0:
95+
for text in request.data:
96+
LogText.objects.create(
97+
demo_log=demo_log,
98+
text=text,
99+
text_type='Output'
100+
)
101+
success_message = {'success': 'OK'}
102+
return Response(success_message, status=status.HTTP_200_OK)

cloudcv/urls.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@
2121
urlpatterns = [
2222
url(r'^admin/', admin.site.urls),
2323
url(r'^api/web/', include('web.urls', namespace='web')),
24-
url(r'^api/demos/', include('demos.urls', namespace='demos'))
24+
url(r'^api/demos/', include('demos.urls', namespace='demos')),
25+
url(r'^api/logs/', include('logs.urls', namespace='logs'))
2526
] + static(MEDIA_URL, document_root=MEDIA_ROOT)

frontend/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@
4545
"redux-thunk": "^2.1.0",
4646
"socket.io": "^2.0.1",
4747
"socket.io-client": "^2.0.1",
48-
"superagent": "^3.0.0"
48+
"superagent": "^3.0.0",
49+
"to-string-loader": "^1.1.5"
4950
},
5051
"devDependencies": {
5152
"autoprefixer": "^7.1.1",
@@ -60,6 +61,7 @@
6061
"babel-preset-react": "^6.16.0",
6162
"babel-preset-react-hmre": "^1.1.1",
6263
"babel-register": "^6.16.3",
64+
"base64-font-loader": "^0.0.4",
6365
"colors": "^1.1.2",
6466
"compression": "^1.6.2",
6567
"cross-env": "4.0.0",

frontend/src/components/App.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ const App = props => {
1616
<Route component={AnalyticsComponent} />
1717
<Switch>
1818
<Route exact path="/" component={HomePageComponent} />
19-
<Route path="/news" component={HomePageComponent} />
2019
<Route path="/team" component={TeamPageComponent} />
2120
<Route path="/projects" component={ProjectPageComponent} />
2221
<Route path="/contact-us" component={HomePageComponent} />
22+
<Route path="/contribute" component={HomePageComponent} />
2323
<Route component={PageNotFoundHandler} />
2424
</Switch>
2525
</main>

frontend/src/components/common/Card.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ const Card = props => {
1010
);
1111
};
1212

13-
const themeClassOptions = ["cv-card-light", "cv-card-dark"];
13+
const themeClassOptions = [
14+
"cv-card-light",
15+
"cv-card-dark",
16+
"cv-card-deep-light"
17+
];
1418

1519
Card.defaultProps = {
1620
children: null,

frontend/src/components/home/HomeBody.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const HomeBody = props => {
2121
<HomeNews />
2222
<HomeShowcase />
2323
<HomeSponsors />
24-
<div className="cv-home-github cv-container">
24+
<div className="cv-home-github cv-container" id="contribute">
2525
<h1 className="cv-home-showcase-heading">{GITHUB_DESC}</h1>
2626
<br />
2727
<p>{GITHUB_STRING}</p>

frontend/src/components/navbar/index.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,21 @@ class Navbar extends Component {
5353
let listItems = [
5454
"",
5555
"Projects",
56-
"News",
5756
"GSoC",
5857
"Team",
5958
"Contribute",
6059
"Contact Us"
6160
];
6261
listItems = listItems.map((path, index) => {
62+
if (path === "GSoC") {
63+
return (
64+
<NavbarItem active={false} key={path}>
65+
<Link to="http://gsoc.cloudcv.org" target="_blank">
66+
{path}
67+
</Link>
68+
</NavbarItem>
69+
);
70+
}
6371
let active = path.toLowerCase() === firstPath;
6472
let formattedPath = path.toLowerCase().replace(/ /g, "-");
6573
return (

frontend/src/components/projects/DemoContainer.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import React from "react";
22
import { PropTypes } from "prop-types";
3+
import styles from "../../styles/demo.scss";
4+
import axios from "axios";
5+
const AJAX_ROOT = process.env.AJAX_ROOT;
36

47
class DemoContainer extends React.Component {
58
constructor(props) {
@@ -8,6 +11,70 @@ class DemoContainer extends React.Component {
811
demo: this.props.demo,
912
height: "auto"
1013
};
14+
this.receiveMessage = this.receiveMessage.bind(this);
15+
this.sendStyleSheet = this.sendStyleSheet.bind(this);
16+
this.saveInput = this.saveInput.bind(this);
17+
this.saveOutput = this.saveOutput.bind(this);
18+
this.log = -1;
19+
window.addEventListener("message", this.receiveMessage, false);
20+
}
21+
22+
componentWillReceiveProps(nextProps) {
23+
if (nextProps.demo.demo_url !== this.state.demo.demo_url)
24+
this.setState({ demo: nextProps.demo });
25+
}
26+
27+
saveInput(data) {
28+
let formData = new FormData();
29+
Object.entries(data).forEach(([key, value]) => {
30+
if (value instanceof Blob) formData.set(key, value, key);
31+
else formData.set(key, value);
32+
});
33+
axios({
34+
method: "post",
35+
url: `${process.env.AJAX_ROOT}/api/logs/${this.state.demo.permalink}/add/`,
36+
data: formData
37+
})
38+
.then(response => {
39+
if (response.status === 200) this.log = response.data.success.id;
40+
})
41+
.catch(error => {});
42+
}
43+
44+
saveOutput(formData) {
45+
if (this.log !== -1)
46+
axios({
47+
method: "post",
48+
url: `${process.env.AJAX_ROOT}/api/logs/${this.log}/output/`,
49+
data: formData
50+
})
51+
.then(response => {
52+
if (response.status === 200) this.log = -1;
53+
})
54+
.catch(error => {});
55+
}
56+
57+
sendStyleSheet() {
58+
let iframeWindow = document.getElementsByTagName("iframe")[0].contentWindow;
59+
let stylesheet = {
60+
action: "STYLESHEET_SEND",
61+
styles: styles.toString()
62+
};
63+
iframeWindow.postMessage(stylesheet, "*");
64+
}
65+
66+
receiveMessage(message) {
67+
switch (message.data.action) {
68+
case "DEMO_ONLOAD":
69+
this.sendStyleSheet();
70+
break;
71+
case "INPUT_SUBMITTED":
72+
this.saveInput(message.data.payload);
73+
break;
74+
case "OUTPUT_SUBMITTED":
75+
this.saveOutput(message.data.payload);
76+
break;
77+
}
1178
}
1279

1380
render() {

0 commit comments

Comments
 (0)