Commit 3803cf21 authored by Evan Prodromou's avatar Evan Prodromou

upload and change avatars

code to upload and change avatars.

combined some code in the settings area, too.

darcs-hash:20080517122045-84dde-8e13994e627805f29679c9533c2f62db81dc0925.gz
parent fac522f4
<?php
/*
* Laconica - a distributed open-source microblogging tool
* Copyright (C) 2008, Controlez-Vous, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('LACONICA')) { exit(1) }
class AvatarAction extends SettingsAction {
function show_form($msg=NULL, $success=false) {
common_show_header(_t('Avatar'));
$this->settings_menu();
$this->message($msg, $success);
$user = common_current_user();
$profile = $user->getProfile();
$original = $profile->getOriginal();
if ($original) {
common_element('img', array('src' => $original->url,
'class' => 'avatar original',
'width' => $original->width,
'height' => $original->height));
}
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
if ($avatar) {
common_element('img', array('src' => $avatar->url,
'class' => 'avatar profile',
'width' => AVATAR_PROFILE_SIZE,
'height' => AVATAR_PROFILE_SIZE));
}
common_start_element('form', array('enctype' => 'multipart/form-data',
'method' => 'POST',
'id' => 'avatar',
'action' =>
common_local_url('avatar')));
common_element('input', array('name' => 'MAX_FILE_SIZE',
'type' => 'hidden',
'id' => 'MAX_FILE_SIZE',
'value' => MAX_AVATAR_SIZE));
common_element('input', array('name' => 'avatarfile',
'type' => 'file',
'id' => 'avatarfile'));
common_element('input', array('name' => 'submit',
'type' => 'submit',
'id' => 'submit'),
_t('Upload'));
}
function handle_post() {
switch ($_FILES['avatarfile']['error']) {
case UPLOAD_ERR_OK: # success, jump out
break;
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
$this->show_form(_t('That file is too big.'));
return;
case UPLOAD_ERR_PARTIAL:
@unlink($_FILES['avatarfile']['tmp_name']);
$this->show_form(_t('Partial upload.'));
return;
default:
$this->show_form(_t('System error uploading file.'));
return;
}
$info = @getimagesize($_FILES['avatarfile']['tmp_name']);
if (!$info) {
@unlink($_FILES['avatarfile']['tmp_name']);
$this->show_form(_t('Not an image or corrupt file.'));
return;
}
switch ($info[2]) {
case IMAGETYPE_GIF:
case IMAGETYPE_JPEG:
case IMAGETYPE_PNG:
break;
default:
$this->show_form(_t('Unsupported image file format.'));
return;
}
$user = common_current_user();
$filename = common_avatar_filename($user, image_type_to_extension($info[2]));
$filepath = common_avatar_path($filename);
if (!move_uploaded_file($_FILES['avatarfile']['tmp_name'], $filepath)) {
@unlink($_FILES['avatarfile']['tmp_name']);
$this->show_form(_t('System error uploading file.'));
return;
}
$avatar = DB_DataObject::factory('avatar');
$avatar->profile_id = $user->id;
$avatar->width = $info[0];
$avatar->height = $info[1];
$avatar->mediatype = image_type_to_mime_type($info[2]);
$avatar->filename = $filename;
$avatar->original = true;
$avatar->url = common_avatar_url($filename);
foreach (array(AVATAR_PROFILE_SIZE, AVATAR_STREAM_SIZE, AVATAR_MINI_SIZE) as $size) {
$scaled[] = $this->scale_avatar($user, $avatar, $size);
}
# XXX: start a transaction here
if (!$this->delete_old_avatars($user)) {
@unlink($filepath);
common_server_error(_t('Error deleting old avatars.'));
return;
}
if (!$avatar->insert()) {
@unlink($filepath);
common_server_error(_t('Error inserting avatar.'));
return;
}
foreach ($scaled as $s) {
if (!$s->insert()) {
common_server_error(_t('Error inserting scaled avatar.'));
return;
}
}
# XXX: end transaction here
$this->show_form(_t('Avatar updated.'), true);
}
function scale_avatar($user, $avatar, $size) {
$image_s = imagecreatetruecolor($size, $size);
$image_a = $this->avatar_to_image($avatar);
$square = min($avatar->width, $avatar->height);
imagecopyresampled($image_s, $image_a, 0, 0, 0, 0,
$size, $size, $square, $square);
$ext = ($avatar->mediattype == 'image/jpeg') ? ".jpg" : ".png";
$filename = common_avatar_filename($user, $ext, $size);
if ($avatar->mediatype == 'image/jpeg') {
imagejpeg($image_s, common_avatar_path($filename));
} else {
imagepng($image_s, common_avatar_path($filename));
}
$scaled = DB_DataObject::factory('avatar');
$scaled->profile_id = $avatar->profile_id;
$scaled->width = $size;
$scaled->height = $size;
$scaled->original = false;
$scaled->mediatype = ($avatar->mediattype == 'image/jpeg') ? 'image/jpeg' : 'image/png';
$scaled->filename = $filename;
$scaled->url = common_avatar_url($filename);
return $scaled;
}
function avatar_to_image($avatar) {
$filepath = common_avatar_path($avatar->filename);
if ($avatar->mediatype == 'image/gif') {
return imagecreatefromgif($filepath);
} else if ($avatar->mediatype == 'image/jpeg') {
return imagecreatefromjpeg($filepath);
} else if ($avatar->mediatype == 'image/png') {
return imagecreatefrompng($filepath);
} else {
common_server_error(_t('Unsupported image type:') . $avatar->mediatype);
return NULL;
}
}
function delete_old_avatars($user) {
$avatar = DB_DataObject::factory('avatar');
$avatar->profile_id = $user->id;
$avatar->find();
while ($avatar->fetch()) {
$avatar->delete();
}
}
}
......@@ -21,26 +21,10 @@ if (!defined('LACONICA')) { exit(1) }
class PasswordAction extends SettingsAction {
function handle($args) {
parent::handle($args);
if (!common_logged_in()) {
common_user_error(_t('Not logged in.'));
return;
}
if ($this->arg('METHOD') == 'POST') {
$this->handle_post();
} else {
$this->show_form();
}
}
function show_form($msg=NULL, $success=false) {
common_show_header(_t('Change password'));
$this->settings_menu();
if ($msg) {
common_element('div', ($success) ? 'success' : 'error',
$msg);
}
$this->message($msg, $success);
common_start_element('form', array('method' => 'POST',
'id' => 'password',
'action' =>
......
......@@ -21,26 +21,10 @@ if (!defined('LACONICA')) { exit(1) }
class ProfilesettingsAction extends SettingsAction {
function handle($args) {
parent::handle($args);
if (!common_logged_in()) {
common_user_error(_t('Not logged in.'));
return;
}
if ($this->arg('METHOD') == 'POST') {
$this->handle_post();
} else {
$this->show_form();
}
}
function show_form($msg=NULL, $success=false) {
common_show_header(_t('Profile settings'));
$this->settings_menu();
if ($msg) {
common_element('div', ($success) ? 'success' : 'error',
$msg);
}
$this->message($msg, $success);
common_start_element('form', array('method' => 'POST',
'id' => 'profilesettings',
'action' =>
......
......@@ -16,10 +16,11 @@ create table profile (
create table avatar (
profile_id integer not null comment 'foreign key to profile table' references profile (id),
original boolean default false comment 'uploaded by user or generated?',
width integer not null comment 'image width',
height integer not null comment 'image height',
original boolean default false comment 'uploaded by user or generated?',
mediatype varchar(32) not null comment 'file type',
filename varchar(255) null comment 'local filename, if local',
url varchar(255) unique key comment 'avatar location',
constraint primary key (profile_id, width, height),
......
+ login
+ register
+ settings
- upload avatar
+ upload avatar
- default avatar
+ change password
+ settings menu
......@@ -18,9 +18,10 @@
+ header menu
+ footer menu
+ disallow direct to PHP files
- require valid nicknames
- store canonical username for comparison and fetch
- use only canonical usernames
- use only canonical email addresses
- require valid nicknames
- common_local_url()
- configuration system ($config)
- RSS 1.0 feeds of a user's notices
......@@ -28,10 +29,12 @@
- RSS 1.0 feed of all public notices
- RDF dump of entire site
- FOAF dump for user
- delete a notice
- licenses
- license on showstream
- license on shownotice
- design from Open Source Web Designs
- TOS checkbox on register
- release 0.1
- delete a notice
- gettext
- subscribe remote
- add subscriber remote
......
......@@ -22,6 +22,7 @@ if (!defined('LACONICA')) { exit(1) }
define('AVATAR_PROFILE_SIZE', 96);
define('AVATAR_STREAM_SIZE', 48);
define('AVATAR_MINI_SIZE', 24);
define('MAX_AVATAR_SIZE', 256 * 1024);
# global configuration object
......@@ -30,6 +31,9 @@ define('AVATAR_MINI_SIZE', 24);
$config =
array('site' =>
array('name' => 'Just another µB'),
'avatar' =>
array('directory' => INSTALLDIR . 'files',
'path' => '/files'),
'dsn' =>
array('phptype' => 'mysql',
'username' => 'stoica',
......@@ -228,6 +232,28 @@ function common_render_content($text) {
return htmlspecialchars($text);
}
// where should the avatar go for this user?
function common_avatar_filename($user, $extension, $size=NULL) {
global $config;
if ($size) {
return $user->id . '-' . $size . $extension;
} else {
return $user->id . '-original' . $extension;
}
}
function common_avatar_path($filename) {
global $config;
return $config['avatar']['directory'] . '/' . $filename;
}
function common_avatar_url($filename) {
global $config;
return $config['avatar']['path'] . '/' . $filename;
}
// XXX: set up gettext
function _t($str) { $str }
......@@ -23,8 +23,33 @@ class SettingsAction extends Action {
function handle($args) {
parent::handle($args);
if (!common_logged_in()) {
common_user_error(_t('Not logged in.'));
return;
}
if ($this->arg('METHOD') == 'POST') {
$this->handle_post();
} else {
$this->show_form();
}
}
# override!
function handle_post() {
return false;
}
function show_form($msg=NULL, $success=false) {
return false;
}
function show_message($msg, $success) {
if ($msg) {
common_element('div', ($success) ? 'success' : 'error',
$msg);
}
}
function settings_menu() {
common_element_start('ul', 'headmenu');
common_menu_item(common_local_url('editprofile'),
......
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