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 "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
|
||||||
|
|
||||||
|
|
|
@ -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 #
|
||||||
##################
|
##################
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
Loading…
Reference in a new issue