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 "web", "/srv/http/ctf"
config.vm.provision :shell, path: "/vagrant/deploy", run: "always", privileged: false
config.vm.provision :shell, :path => "scripts/setup.sh"
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 werkzeug import secure_filename
from flask import current_app as app
from voluptuous import Schema, Length, Required
@ -8,11 +9,14 @@ from schemas import verify_to_schema, check
import datetime
import logger
import os
import re
import requests
import team
import utils
from PIL import Image
###############
# USER ROUTES #
###############
@ -185,6 +189,46 @@ def user_avatar(uid):
return send_file("pfp/%d.png" % uid, mimetype="image/png")
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 #
##################

View file

@ -77,6 +77,7 @@ app.config(function($routeProvider, $locationProvider) {
app.controller("mainController", ["$scope", "$http", function($scope, $http) {
$scope.config = { navbar: { } };
$scope.timestamp = Date.now();
$.get("/api/user/status", function(result) {
if (result["success"] == 1) {
delete result["success"];
@ -192,7 +193,6 @@ app.controller("settingsController", ["$controller", "$scope", "$http", function
$controller("mainController", { $scope: $scope });
$.get("/api/user/info", {}, function(result) {
if (result["success"] == 1) {
console.log(result["user"]);
$scope.user = result["user"];
}
$scope.$apply();
@ -204,7 +204,7 @@ function display_message(containerId, alertType, message, callback) {
$("#" + containerId).hide().slideDown("fast", "swing", function() {
window.setTimeout(function () {
$("#" + 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-body">
<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>
</div>
<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="col-sm-3 col-xs-12">
<div class="panel panel-default">
@ -21,16 +42,23 @@
<label>Profile Picture</label>
<div class="row">
<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 class="col-sm-10">
<p>
<a href="javascript:upload_new_picture();" class="btn btn-primary">Upload new picture</a>
<a href="javascript:remove_profile_picture();" class="btn btn-default">Remove profile picture</a>
</p>
<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>
<div class="row">
<div class="btn-group">
<div class="btn btn-primary btn-file" id="file_upload">
<i class="fa fa-fw fa-upload"></i> Upload new picture
<input type="file" name="file" id="file" accept="image/*" />
</div>
<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>
@ -82,4 +110,83 @@
offset: $("#navbar").outerHeight(),
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>