Image uploading finally done!
This commit is contained in:
parent
1b16b3d5e0
commit
7cc0b64d1e
5 changed files with 173 additions and 11 deletions
1
Vagrantfile
vendored
1
Vagrantfile
vendored
|
@ -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
|
||||
|
||||
|
|
|
@ -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 #
|
||||
##################
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
};
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
Loading…
Add table
Reference in a new issue