Commit 087e0074 by swdanielli

manage file uploading with pyfilesystem

parent e377d6c3
"""TO-DO: Write a description of what this XBlock is.""" """TO-DO: Write a description of what this XBlock is."""
import json import json, string, random, re
import pkg_resources import pkg_resources
from mako.template import Template from mako.template import Template
...@@ -10,6 +10,12 @@ from xblock.core import XBlock ...@@ -10,6 +10,12 @@ from xblock.core import XBlock
from xblock.fields import Scope, Integer, String, BlockScope, List from xblock.fields import Scope, Integer, String, BlockScope, List
from xblock.fragment import Fragment from xblock.fragment import Fragment
from fs.s3fs import S3FS
from webob.response import Response
aws_access_key_env='AKIAIRDHSV6YZJZ4RFGA'
aws_secret_key_env='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'
class HelpResource(dict): class HelpResource(dict):
def __str__(self): def __str__(self):
return json.dumps(self) return json.dumps(self)
...@@ -129,6 +135,36 @@ class RecommenderXBlock(XBlock): ...@@ -129,6 +135,36 @@ class RecommenderXBlock(XBlock):
print "Downvote clicked!" print "Downvote clicked!"
return {"Success": True} return {"Success": True}
@XBlock.handler
def upload_screenshot(self, request, suffix=''):
chars=string.ascii_uppercase + string.digits
size=11
fileDir = 'uploads/'
if re.search('.png$', str(request.POST['file'].file)):
filetype = '.png'
elif re.search('.jpg$', str(request.POST['file'].file)):
filetype = '.jpg'
else:
print "Wrong file type"
return {"Success": False}
myS3FS = S3FS('danielswli', aws_access_key=aws_access_key_env, aws_secret_key=aws_secret_key_env)
while True:
file_id = ''.join(random.choice(chars) for _ in range(size))
filename = fileDir + file_id + filetype
if not myS3FS.exists(filename):
break
content = request.POST['file'].file.read()
fhwrite = myS3FS.open(filename, 'wb')
fhwrite.write(content)
fhwrite.close()
myS3FS.makepublic(filename)
response = Response()
response.body = filename
response.headers['Content-Type'] = 'text/plain'
print 'before return'
return response
@XBlock.json_handler @XBlock.json_handler
def add_resource(self, data, suffix=''): def add_resource(self, data, suffix=''):
......
...@@ -32,15 +32,15 @@ ...@@ -32,15 +32,15 @@
<div class='pagination'> </div> <div class='pagination'> </div>
<div class="recommender_description"> <div class="recommender_description">
<div class="descriptionImg"> <div class="descriptionImg">
<div> This is a list of resources your fellow students <div> This is a list of resources your fellow students
thought might be helpful. If you find another useful thought might be helpful. If you find another useful
resource, either on edx.org or elsewhere, please add resource, either on edx.org or elsewhere, please add
it. If you can improve the description or preview of a it. If you can improve the description or preview of a
resource, please do so as well. If you find a resource resource, please do so as well. If you find a resource
helpful, upvote it. If it's not so helpful, downvote helpful, upvote it. If it&rsquo;s not so helpful, downvote
it. If it has issues (illegal material, incorrect, etc.), it. If it has issues (illegal material, incorrect, etc.),
please flag it and let us know the reason. </div> please flag it and let us know the reason. </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
...@@ -48,11 +48,11 @@ ...@@ -48,11 +48,11 @@
<div class='recommender_modify_title_container'><div class='backToViewButton'>&lt; Related resources</div><div class='recommender_modify_title'></div></div> <div class='recommender_modify_title_container'><div class='backToViewButton'>&lt; Related resources</div><div class='recommender_modify_title'></div></div>
<div class="flagSourceBlock"> <div class="flagSourceBlock">
<div class="flagSourceBlockTitle">Why would you like to flag this resource?</div> <div class="flagSourceBlockTitle">Why would you like to flag this resource?</div>
<input type="text" <input type="text"
class="flag_reason" class="flag_reason"
style="height: 25px; position: relative; left: 10px; width:100%" style="height: 25px; position: relative; left: 10px; width:100%"
name="flag_rationale" name="flag_rationale"
placeholder="Reason for why this resource should be removed"/><br> placeholder="Reason for why this resource should be removed"/><br/>
<input type="button" value="Flag resource" class="flag_reason_submit" style="margin-top: 0.5em;"> <input type="button" value="Flag resource" class="flag_reason_submit" style="margin-top: 0.5em;">
</div> </div>
<div class="editSourceBlock"> <div class="editSourceBlock">
...@@ -60,18 +60,17 @@ ...@@ -60,18 +60,17 @@
<div class="recommender_add"> <div class="recommender_add">
<div class="addSourceBlockTitle">Suggest a resource which can help other students with this problem.</div> <div class="addSourceBlockTitle">Suggest a resource which can help other students with this problem.</div>
Description <input type="text" Description <input type="text"
class="in_title" class="in_title"
style="height: 25px; position: relative; left: 10px; width:100%" style="height: 25px; position: relative; left: 10px; width:100%"
placeholder="Provide a meaningful description so other students know whether this is useful to them"/><br/> placeholder="Provide a meaningful description so other students know whether this is useful to them"/><br/>
Location <input type="text" Location <input type="text"
class="in_url" class="in_url"
style="height: 25px; position: relative; left: 22px; width:100%" style="height: 25px; position: relative; left: 22px; width:100%"
placeholder="http://en.wikipedia.org/wiki/Edx"/><br/> placeholder="http://en.wikipedia.org/wiki/Edx"/><br/>
<form id="addResourceForm" action="http://danielswli.s3.amazonaws.com/" method="post" enctype="multipart/form-data"> <form method="post" id="addResourceForm">
<input type="hidden" name="acl" value="public-read"> Previewing screenshot: <input type="file" name="file"><br/>
<input type="hidden" name="Content-Type" value="image/jpeg"> <div class='in_filename hidden'></div>
<input type="hidden" name="AWSAccessKeyId" value="AKIAIRDHSV6YZJZ4RFGA"> <input type="button" value="Add resource" class="add_submit" style="margin-top: 0.5em" disabled >
<input type="hidden" name="key" value="">
</form> </form>
</div> </div>
</div> </div>
......
...@@ -4,6 +4,7 @@ function RecommenderXBlock(runtime, element) { ...@@ -4,6 +4,7 @@ function RecommenderXBlock(runtime, element) {
var addResourceUrl = runtime.handlerUrl(element, 'add_resource'); var addResourceUrl = runtime.handlerUrl(element, 'add_resource');
var editResourceUrl = runtime.handlerUrl(element, 'edit_resource'); var editResourceUrl = runtime.handlerUrl(element, 'edit_resource');
var flagResourceUrl = runtime.handlerUrl(element, 'flag_resource'); var flagResourceUrl = runtime.handlerUrl(element, 'flag_resource');
var uploadScreenshotUrl = runtime.handlerUrl(element, 'upload_screenshot');
var baseUrl = 'http://s3-us-west-2.amazonaws.com/danielswli/'; var baseUrl = 'http://s3-us-west-2.amazonaws.com/danielswli/';
var currentPage = 1; var currentPage = 1;
...@@ -106,24 +107,12 @@ function RecommenderXBlock(runtime, element) { ...@@ -106,24 +107,12 @@ function RecommenderXBlock(runtime, element) {
backToView(); backToView();
}); });
/* prepare the form for uploading file to S3: TODO, handle this with pyfilesystem */
var policyBase64 = 'CnsiZXhwaXJhdGlvbiI6ICIyMDIwLTEyLTAxVDEyOjAwOjAwLjAwMFoiLAogICJjb25kaXRpb25zIjogWwogICAgeyJidWNrZXQiOiAiZGFuaWVsc3dsaSJ9LAogICAgWyJzdGFydHMtd2l0aCIsICIka2V5IiwgInVwbG9hZHMvIl0sCiAgICB7ImFjbCI6ICJwdWJsaWMtcmVhZCJ9LAogICAgWyJzdGFydHMtd2l0aCIsICIkQ29udGVudC1UeXBlIiwgIiJdLAogICAgWyJjb250ZW50LWxlbmd0aC1yYW5nZSIsIDAsIDUyNDI4ODAwMF0KICBdCn0=';
var signature = 'uRVljXwwHfM5K351eTL2MbYLwcI=';
$('#addResourceForm').append('<input type="hidden" name="Policy" value="' + policyBase64 + '">'
+ '<input type="hidden" name="Signature" value="' + signature + '">'
+ 'Previewing screenshot: <input type="file" name="file"><br>'
//+ '<input type="submit" class="submitAddResourceForm" name="submit" value="Upload File" style="margin-top: 0.5em">'
+ '<input type="button" value="Add resource" class="add_submit" style="margin-top: 0.5em" disabled >');
/* initialize add resource mode */ /* initialize add resource mode */
function addResourceReset() { function addResourceReset() {
$('.in_title').val(''); $('.in_title').val('');
$('.in_url').val(''); $('.in_url').val('');
$('#addResourceForm').find("input[name='file']").val('') $('#addResourceForm').find("input[name='file']").val('');
$('.in_filename').text('');
/* get time for unique filenames: TODO, randomize filenames */
var key = "uploads/" + (new Date).getTime();
$('#addResourceForm').find("input[name='key']").val(key);
$('.add_submit').attr('disabled', true); $('.add_submit').attr('disabled', true);
} }
...@@ -143,15 +132,25 @@ function RecommenderXBlock(runtime, element) { ...@@ -143,15 +132,25 @@ function RecommenderXBlock(runtime, element) {
/* upload once student select a file */ /* upload once student select a file */
$('#addResourceForm').find("input[name='file']").change(function (){ $('#addResourceForm').find("input[name='file']").change(function (){
if ($(this).val() == '') { return false; } if ($(this).val() == '') { return false; }
$("#addResourceForm").submit(); var formDiv = $(this).parent();
var data = new FormData($(formDiv)[0]);
$.ajax({
type: 'POST',
url: uploadScreenshotUrl,
data: data,
contentType: false,
cache: false,
processData: false,
async: false,
/* WANRING: I DON'T KNOW WHY IT ALWAYS ACTIVATE ERROR (COMPLETE) EVENT, INSTEAD OF SUCCESS, ALTHOUGH IT ACTIVATES SUCCESS CORRECTLY IN XBLOCK-SDK */
complete: function(data) {
/* save filename in hidden div */
$('.in_filename').text(data.responseText);
enableAddSubmit();
},
});
}); });
$("#addResourceForm").submit( function(e) {
if ($('#addResourceForm').find("input[name='file']").val() == '') { return false; }
enableAddSubmit();
return true;
});
/* submit the resource, save to database, update the current view */ /* submit the resource, save to database, update the current view */
$('.add_submit').click(function() { $('.add_submit').click(function() {
/* data: parameter passed to database */ /* data: parameter passed to database */
...@@ -159,7 +158,7 @@ function RecommenderXBlock(runtime, element) { ...@@ -159,7 +158,7 @@ function RecommenderXBlock(runtime, element) {
data['resource'] = {}; data['resource'] = {};
data['resource']['url'] = $('.in_url').val(); data['resource']['url'] = $('.in_url').val();
data['resource']['title'] = $('.in_title').val(); data['resource']['title'] = $('.in_title').val();
data['resource']['description'] = baseUrl + $(this).parent().find("input[name='key']").val(); data['resource']['description'] = baseUrl + $(this).parent().find('.in_filename').text();
$.ajax({ $.ajax({
type: "POST", type: "POST",
...@@ -313,24 +312,15 @@ function RecommenderXBlock(runtime, element) { ...@@ -313,24 +312,15 @@ function RecommenderXBlock(runtime, element) {
$('.recommender_modify_title').text('Edit existing resource'); $('.recommender_modify_title').text('Edit existing resource');
$('.editSourceBlock').empty(); $('.editSourceBlock').empty();
/* get time for unique filenames: TODO, randomize filenames */ var uploadForm = '<form id="editResourceForm" method="post">'
var key = "uploads/" + (new Date).getTime(); + 'Previewing screenshot: <input type="file" name="file"><br/>'
/* prepare the form for uploading file to S3: TODO, handle this with pyfilesystem */ + '<div class="edit_filename hidden"></div>'
var path = 'http://danielswli.s3.amazonaws.com/';
var uploadForm = '<form id="editResourceForm" action="' + path + '" method="post" enctype="multipart/form-data">'
+ '<input type="hidden" name="key" value="' + key + '">'
+ '<input type="hidden" name="acl" value="public-read">'
+ '<input type="hidden" name="Content-Type" value="image/jpeg">'
+ '<input type="hidden" name="AWSAccessKeyId" value="AKIAIRDHSV6YZJZ4RFGA">'
+ '<input type="hidden" name="Policy" value="' + policyBase64 + '">'
+ '<input type="hidden" name="Signature" value="' + signature + '">'
+ 'Previewing screenshot: <input type="file" name="file"><br>'
+ '<input type="button" value="Save change" class="edit_submit" style="margin-top: 0.5em" disabled></form>'; + '<input type="button" value="Save change" class="edit_submit" style="margin-top: 0.5em" disabled></form>';
$('.editSourceBlock').append( $('.editSourceBlock').append(
'<div class="editSourceBlockTitle">Edit the description, hypelink, and previewing screenshot for the selected resource</div>' + '<div class="editSourceBlockTitle">Edit the description, hypelink, and previewing screenshot for the selected resource</div>' +
'Description: ' + '<input type="text" class="edit_title" style="height: 25px; position: relative; left: 10px;"><br>' + 'Description: ' + '<input type="text" class="edit_title" style="height: 25px; position: relative; left: 10px;"><br/>' +
'HyperLink: <input type="text" class="edit_url" style="height: 25px; position: relative; left: 22px;"><br>' + uploadForm); 'HyperLink: <input type="text" class="edit_url" style="height: 25px; position: relative; left: 22px;"><br/>' + uploadForm);
/* initialize the text area */ /* initialize the text area */
$('.edit_title').val($(this).parent().parent().find('.recommender_title').find('a').text()); $('.edit_title').val($(this).parent().parent().find('.recommender_title').find('a').text());
...@@ -355,15 +345,24 @@ function RecommenderXBlock(runtime, element) { ...@@ -355,15 +345,24 @@ function RecommenderXBlock(runtime, element) {
/* upload once student select a file */ /* upload once student select a file */
$('#editResourceForm').find("input[name='file']").change(function (){ $('#editResourceForm').find("input[name='file']").change(function (){
if ($(this).val() == '') { return false; } if ($(this).val() == '') { return false; }
$("#editResourceForm").submit(); var formDiv = $(this).parent();
var data = new FormData($(formDiv)[0]);
$.ajax({
type: 'POST',
url: uploadScreenshotUrl,
data: data,
contentType: false,
cache: false,
processData: false,
async: false,
/* WANRING: I DON'T KNOW WHY IT ALWAYS ACTIVATE ERROR (COMPLETE) EVENT, INSTEAD OF SUCCESS, ALTHOUGH IT ACTIVATES SUCCESS CORRECTLY IN XBLOCK-SDK */
complete: function(data) {
/* save filename in hidden div */
$('.edit_filename').text(data.responseText);
enableEditSubmit();
},
});
}); });
$("#editResourceForm").submit( function(e) {
if ($('#editResourceForm').find("input[name='file']").val() == '') { return false; }
enableEditSubmit();
return true;
});
/* submit the edited resource, save to database, update the current view */ /* submit the edited resource, save to database, update the current view */
$('.edit_submit').click(function() { $('.edit_submit').click(function() {
...@@ -373,7 +372,7 @@ function RecommenderXBlock(runtime, element) { ...@@ -373,7 +372,7 @@ function RecommenderXBlock(runtime, element) {
data['url'] = $('.edit_url').val(); data['url'] = $('.edit_url').val();
data['title'] = $('.edit_title').val(); data['title'] = $('.edit_title').val();
if (data['url'] == '' || data['title'] == '') { return; } if (data['url'] == '' || data['title'] == '') { return; }
if ($('#editResourceForm').find("input[name='file']").val() != '') { data['description'] = baseUrl + key; } if ($(this).parent().find('.edit_filename').text() != '') { data['description'] = baseUrl + $(this).parent().find('.edit_filename').text(); }
$.ajax({ $.ajax({
type: "POST", type: "POST",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment