]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
upload and change avatars
authorEvan Prodromou <evan@prodromou.name>
Sat, 17 May 2008 12:20:45 +0000 (08:20 -0400)
committerEvan Prodromou <evan@prodromou.name>
Sat, 17 May 2008 12:20:45 +0000 (08:20 -0400)
code to upload and change avatars.

combined some code in the settings area, too.

darcs-hash:20080517122045-84dde-8e13994e627805f29679c9533c2f62db81dc0925.gz

actions/avatar.php [new file with mode: 0644]
actions/password.php
actions/profilesettings.php
db/stoica.sql
doc/TODO
lib/common.php
lib/settingsaction.php

diff --git a/actions/avatar.php b/actions/avatar.php
new file mode 100644 (file)
index 0000000..b715e02
--- /dev/null
@@ -0,0 +1,208 @@
+<?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();
+               }
+       }
+}
+
index 31831d3a935e5a7db189b7fd455f16eac50ef24a..3fd94b66ad7b486784d4d3b98e41a91f5857a4e5 100644 (file)
@@ -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' => 
index b87cea7de2596df49a43b673a42fdce23c9d244d..95462133ee3fb5a5b42e7106375d83c74d95cffa 100644 (file)
@@ -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' => 
index 7ee8f6ff8b9bc32b4bf7ab0fb3105b73b3201cb6..1f2b28d95bbbb81f2412c190151df19609c81ff2 100644 (file)
@@ -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),
index cd9ac05df055afef86c575f01047d47bdb3ac18a..08df348e2f8297c797f40bb985996b020f7d7fda 100644 (file)
--- a/doc/TODO
+++ b/doc/TODO
@@ -1,7 +1,7 @@
 + login
 + register
 + settings
-- upload avatar
++ upload avatar
 - default avatar
 + change password
 + settings menu
 + 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
 - 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
index f30096796b1fc641ac2c5ebcf395d8af232a3d89..b4c2f9b6e7e24ad60bdc1911700353a63fa6244a 100644 (file)
@@ -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 }
index db07bdef926579adbdb9ae559e2ad9db07dcd126..1795969f9082be38e000709d1386de5f8969683a 100644 (file)
@@ -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'),