Image uploading finally done!

This commit is contained in:
Michael Zhang 2016-03-03 18:27:10 -06:00
parent 1b16b3d5e0
commit 7cc0b64d1e
5 changed files with 173 additions and 11 deletions

1
Vagrantfile vendored
View file

@ -13,6 +13,7 @@ Vagrant.configure(2) do |config|
config.vm.synced_folder "scripts", "/home/vagrant/scripts" config.vm.synced_folder "scripts", "/home/vagrant/scripts"
config.vm.synced_folder "web", "/srv/http/ctf" config.vm.synced_folder "web", "/srv/http/ctf"
config.vm.provision :shell, path: "/vagrant/deploy", run: "always", privileged: false
config.vm.provision :shell, :path => "scripts/setup.sh" config.vm.provision :shell, :path => "scripts/setup.sh"
config.ssh.forward_agent = true config.ssh.forward_agent = true

View file

@ -1,4 +1,5 @@
from flask import Blueprint, make_response, session, request, redirect, url_for, send_file from flask import Blueprint, make_response, session, request, redirect, url_for, send_file
from werkzeug import secure_filename
from flask import current_app as app from flask import current_app as app
from voluptuous import Schema, Length, Required from voluptuous import Schema, Length, Required
@ -8,11 +9,14 @@ from schemas import verify_to_schema, check
import datetime import datetime
import logger import logger
import os
import re import re
import requests import requests
import team import team
import utils import utils
from PIL import Image
############### ###############
# USER ROUTES # # USER ROUTES #
############### ###############
@ -185,6 +189,46 @@ def user_avatar(uid):
return send_file("pfp/%d.png" % uid, mimetype="image/png") return send_file("pfp/%d.png" % uid, mimetype="image/png")
return abort(404) return abort(404)
@blueprint.route("/avatar/upload", methods=["POST"])
@api_wrapper
def user_avatar_upload():
logged_in = is_logged_in()
if not logged_in:
raise WebException("You're not logged in.")
_user = get_user().first()
f = request.files["file"]
if f is None:
raise WebException("Please upload something.")
fname = "/tmp/" + secure_filename(utils.generate_string())
f.save(fname)
try:
pfp = "pfp/%d.png" % _user.uid
os.remove(pfp)
im = Image.open(fname)
im = im.resize((256, 256), Image.ANTIALIAS)
im.save(open(pfp, "w"), "PNG")
return { "success": 1, "message": "Uploaded!" }
except Exception, e:
raise WebException(str(e))
@blueprint.route("/avatar/remove", methods=["POST"])
@api_wrapper
def user_avatar_remove():
logged_in = is_logged_in()
if not logged_in:
raise WebException("You're not logged in.")
_user = get_user().first()
try:
pfp = "pfp/%d.png" % _user.uid
os.remove(pfp)
return { "success": 1, "message": "Removed!" }
except Exception, e:
raise WebException(str(e))
################## ##################
# USER FUNCTIONS # # USER FUNCTIONS #
################## ##################

View file

@ -77,6 +77,7 @@ app.config(function($routeProvider, $locationProvider) {
app.controller("mainController", ["$scope", "$http", function($scope, $http) { app.controller("mainController", ["$scope", "$http", function($scope, $http) {
$scope.config = { navbar: { } }; $scope.config = { navbar: { } };
$scope.timestamp = Date.now();
$.get("/api/user/status", function(result) { $.get("/api/user/status", function(result) {
if (result["success"] == 1) { if (result["success"] == 1) {
delete result["success"]; delete result["success"];
@ -192,7 +193,6 @@ app.controller("settingsController", ["$controller", "$scope", "$http", function
$controller("mainController", { $scope: $scope }); $controller("mainController", { $scope: $scope });
$.get("/api/user/info", {}, function(result) { $.get("/api/user/info", {}, function(result) {
if (result["success"] == 1) { if (result["success"] == 1) {
console.log(result["user"]);
$scope.user = result["user"]; $scope.user = result["user"];
} }
$scope.$apply(); $scope.$apply();
@ -204,7 +204,7 @@ function display_message(containerId, alertType, message, callback) {
$("#" + containerId).hide().slideDown("fast", "swing", function() { $("#" + containerId).hide().slideDown("fast", "swing", function() {
window.setTimeout(function () { window.setTimeout(function () {
$("#" + containerId).slideUp("fast", "swing", callback); $("#" + containerId).slideUp("fast", "swing", callback);
}, message.length * 75); }, message.length * 55);
}); });
}; };
@ -402,3 +402,13 @@ var accept_invitation_request = function(uid) {
} }
}); });
}; };
// settings page
var remove_profile_picture = function() {
api_call("POST", "/api/user/avatar/remove", { }, function(result) {
if (result["success"] == 1) {
location.reload(true);
}
});
};

View file

@ -4,7 +4,7 @@
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-body"> <div class="panel-body">
<div style="width:100%;max-width:100%;"> <div style="width:100%;max-width:100%;">
<img src="/api/user/avatar/{{ user.uid }}" id="avatar" style="width:100%;max-height:256px;" /> <img src="/api/user/avatar/{{ user.uid }}?{{ timestamp }}" id="avatar" style="width:100%;max-height:256px;" />
<small style="display:block;text-align:right;" ng-show="user['me']==true"><a href="/settings#profile">Edit Picture</a></small> <small style="display:block;text-align:right;" ng-show="user['me']==true"><a href="/settings#profile">Edit Picture</a></small>
</div> </div>
<h2 style="margin:0px;font-weight:bold;font-size:2em;">{{ user.name }}</h2> <h2 style="margin:0px;font-weight:bold;font-size:2em;">{{ user.name }}</h2>

View file

@ -1,3 +1,24 @@
<style>
.btn-file {
position: relative;
overflow: hidden;
}
.btn-file input[type=file] {
position: absolute;
top: 0;
right: 0;
min-width: 100%;
min-height: 100%;
font-size: 100px;
text-align: right;
filter: alpha(opacity=0);
opacity: 0;
background: red;
cursor: inherit;
display: block;
}
</style>
<div class="row"> <div class="row">
<div class="col-sm-3 col-xs-12"> <div class="col-sm-3 col-xs-12">
<div class="panel panel-default"> <div class="panel panel-default">
@ -21,16 +42,23 @@
<label>Profile Picture</label> <label>Profile Picture</label>
<div class="row"> <div class="row">
<div class="col-sm-2"> <div class="col-sm-2">
<img src="/api/user/avatar/{{ user.uid }}" id="avatar" style="width:100%;max-height:256px;" /> <img src="/api/user/avatar/{{ user.uid }}?{{ timestamp }}" id="avatar" style="width:100%;max-height:256px;" />
</div> </div>
<div class="col-sm-10"> <div class="col-sm-10">
<p> <div class="row">
<a href="javascript:upload_new_picture();" class="btn btn-primary">Upload new picture</a> <div class="btn-group">
<a href="javascript:remove_profile_picture();" class="btn btn-default">Remove profile picture</a> <div class="btn btn-primary btn-file" id="file_upload">
</p> <i class="fa fa-fw fa-upload"></i> Upload new picture
<p> <input type="file" name="file" id="file" accept="image/*" />
<i>If you remove your picture, an automatically generated <a href="http://en.wikipedia.org/wiki/Identicon" target="_blank">identicon</a> will be used.</i> </div>
</p> <a class="btn btn-default" href="javascript:remove_profile_picture();">
<i class="fa fa-fw fa-trash"></i> Remove profile picture
</a>
</div>
</div>
<div class="row">
<p><i>If you remove your picture, an automatically generated <a href="http://en.wikipedia.org/wiki/Identicon" target="_blank">identicon</a> will be used.</i></p>
</div1>
</div> </div>
</div> </div>
</div> </div>
@ -82,4 +110,83 @@
offset: $("#navbar").outerHeight(), offset: $("#navbar").outerHeight(),
updateURL: false updateURL: false
}); });
var dataURItoBlob = function(dataURI) {
var byteString = atob(dataURI.split(",")[1]);
var mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0];
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
var blob = new Blob([ ab ], { type: mimeString });
return blob;
}
var MAX_SIZE = 256;
var uploadListener = function(e) {
try {
$("#file_upload").attr("disabled", "disabled");
$("#file_upload").html("<i class='fa fa-fw fa-circle-o-notch fa-spin'></i> Uploading...");
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = (function(_file) {
return function(progress) {
var img = document.createElement("img");
img.src = progress.target.result;
var width = img.width;
var height = img.height;
if (width > height) {
if (width > MAX_SIZE) {
height *= MAX_SIZE / width;
width = MAX_SIZE;
}
} else {
if (height > MAX_SIZE) {
width *= MAX_SIZE / height;
height = MAX_SIZE;
}
}
img.cwidth = width;
img.cheight = height;
var data = new FormData();
data.append("file", dataURItoBlob(img.src));
data.append("csrf_token", $.cookie("csrf_token"));
$.ajax({
type: "POST",
url: "/api/user/avatar/upload",
data: data,
processData: false,
contentType: false,
}).done(function(result) {
if (result["success"] == 1) {
$("#file_upload").removeClass("btn-primary");
$("#file_upload").addClass("btn-success");
$("#file_upload").html("<i class='fa fa-fw fa-check'></i> Done! Reloading...");
location.reload(true);
}
}).fail(function() {
$("#file_upload").removeClass("btn-primary");
$("#file_upload").addClass("btn-danger");
$("#file_upload").html("<i class='fa fa-fw fa-ban'></i> Error. Reloading...");
location.reload(true);
});
};
})(file);
reader.readAsDataURL(file);
} catch (e) {
console.log(e);
$("#file_upload").removeClass("btn-primary");
$("#file_upload").addClass("btn-danger");
$("#file_upload").html("<i class='fa fa-fw fa-ban'></i> Error. Reloading...");
location.reload(true);
}
};
$(document).ready(function() {
if (!(window.File && window.FileReader && window.FileList && window.Blob)) {
console.log("Your browser doesn't support file upload.");
} else {
document.getElementById("file").addEventListener("change", uploadListener, false);
};
});
</script> </script>