registration

This commit is contained in:
Hannes Mannerheim 2013-09-02 18:13:15 +02:00
parent 8f47c3b4f9
commit e9e21fd87e
9 changed files with 659 additions and 27 deletions

View File

@ -22,9 +22,11 @@ along with Qvitter. If not, see <http://www.gnu.org/licenses/>.
Setup Setup
----- -----
You need a webserver with PHP support. 1. You need a webserver with PHP support.
Edit settings.php. 2. Edit settings.php.
3. You should really put some security-by-obscurity-stuff in the registration process. E-mail h@nnesmannerhe.im if you want to copy mine.
(Qvitter uses a slightly modified statusnet API. Some things will not work (Qvitter uses a slightly modified statusnet API. Some things will not work
if you connect to a site with standard API. Files are included if you want if you connect to a site with standard API. Files are included if you want
@ -36,13 +38,11 @@ TODO
1. Join _new_ external groups and follow _new_ external users ("New" meaning users/groups that the server don't know yet) 1. Join _new_ external groups and follow _new_ external users ("New" meaning users/groups that the server don't know yet)
2. Auto suggest mentions 2. Creating groups, make admin, block user
3. Register 3. Background image uploading/editing
4. Background image uploading/editing 4. Auto suggest mentions
5. Color theme
6. Auto url-shortening setting under queet box 6. Auto url-shortening setting under queet box
@ -64,10 +64,10 @@ TODO
15. Queet-page 15. Queet-page
16. Admin-interface
16. New api for serving _number_ of new items in several streams (to show number of new items in menu/history) 16. New api for serving _number_ of new items in several streams (to show number of new items in menu/history)
17. New "expand queet" api for getting conversation, retweets, favs and attachment in the same request 17. New "expand queet" api for getting conversation, retweets, favs and attachment in the same request
18. DMs
19. Node.js long polling server and an new api that serve aggregate of all polling users requests in one go 19. Node.js long polling server and an new api that serve aggregate of all polling users requests in one go

View File

@ -7,6 +7,10 @@
* actions/apiexternalprofileshow.php New api action * actions/apiexternalprofileshow.php New api action
* actions/apigroupadmins.php New api action * actions/apigroupadmins.php New api action
* actions/apiaccountupdatelinkcolor.php New api action * actions/apiaccountupdatelinkcolor.php New api action
* actions/apiaccountupdatelinkcolor.php New api action
* actions/apichecknickname.php New api action
* actions/apiaccountregister.php New api action
* lib/apiaction.php * lib/apiaction.php
@ -95,6 +99,13 @@
$m->connect('api/account/update_background_color.json', $m->connect('api/account/update_background_color.json',
array('action' => 'ApiAccountUpdateBackgroundColor')); array('action' => 'ApiAccountUpdateBackgroundColor'));
$m->connect('api/account/register.json',
array('action' => 'ApiAccountRegister'));
$m->connect('api/check_nickname.json',
array('action' => 'ApiCheckNickname'));
- also, tags need regexp to work with unicode charachters, e.g. farsi and arabic: - also, tags need regexp to work with unicode charachters, e.g. farsi and arabic:

View File

@ -0,0 +1,257 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Register account
*
* PHP version 5
*
* LICENCE: 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/>.
*
* @category API
* @package StatusNet
* @author Hannes Mannerheim <h@nnesmannerhe.im>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
class ApiAccountRegisterAction extends ApiAction
{
/**
* Has there been an error?
*/
var $error = null;
/**
* Have we registered?
*/
var $registered = false;
/**
* Are we processing an invite?
*/
var $invite = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*/
function prepare($args)
{
parent::prepare($args);
$this->code = $this->trimmed('code');
if (empty($this->code)) {
common_ensure_session();
if (array_key_exists('invitecode', $_SESSION)) {
$this->code = $_SESSION['invitecode'];
}
}
if (common_config('site', 'inviteonly') && empty($this->code)) {
// TRANS: Client error displayed when trying to register to an invite-only site without an invitation.
$this->clientError(_('Sorry, only invited people can register.'),404,'json');
return false;
}
if (!empty($this->code)) {
$this->invite = Invitation::staticGet('code', $this->code);
if (empty($this->invite)) {
// TRANS: Client error displayed when trying to register to an invite-only site without a valid invitation.
$this->clientError(_('Sorry, invalid invitation code.'),404,'json');
return false;
}
// Store this in case we need it
common_ensure_session();
$_SESSION['invitecode'] = $this->code;
}
return true;
}
/**
* Handle the request
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
$this->clientError(
_('This method requires a POST.'),
400, $this->format
);
return;
} else {
$nickname = $this->trimmed('nickname');
$email = $this->trimmed('email');
$fullname = $this->trimmed('fullname');
$homepage = $this->trimmed('homepage');
$bio = $this->trimmed('bio');
$location = $this->trimmed('location');
// We don't trim these... whitespace is OK in a password!
$password = $this->arg('password');
$confirm = $this->arg('confirm');
// invitation code, if any
$code = $this->trimmed('code');
if ($code) {
$invite = Invitation::staticGet($code);
}
if (common_config('site', 'inviteonly') && !($code && $invite)) {
// TRANS: Client error displayed when trying to register to an invite-only site without an invitation.
$this->clientError(_('Sorry, only invited people can register.'),404,'json');
return;
}
// Input scrubbing
try {
$nickname = Nickname::normalize($nickname);
} catch (NicknameException $e) {
$this->showForm($e->getMessage());
}
$email = common_canonical_email($email);
if ($email && !Validate::email($email, common_config('email', 'check_domain'))) {
// TRANS: Form validation error displayed when trying to register without a valid e-mail address.
$this->clientError(_('Not a valid email address.'),404,'json');
} else if ($this->nicknameExists($nickname)) {
// TRANS: Form validation error displayed when trying to register with an existing nickname.
$this->clientError(_('Nickname already in use. Try another one.'),404,'json');
} else if (!User::allowed_nickname($nickname)) {
// TRANS: Form validation error displayed when trying to register with an invalid nickname.
$this->clientError(_('Not a valid nickname.'),404,'json');
} else if ($this->emailExists($email)) {
// TRANS: Form validation error displayed when trying to register with an already registered e-mail address.
$this->clientError(_('Email address already exists.'),404,'json');
} else if (!is_null($homepage) && (strlen($homepage) > 0) &&
!Validate::uri($homepage,
array('allowed_schemes' =>
array('http', 'https')))) {
// TRANS: Form validation error displayed when trying to register with an invalid homepage URL.
$this->clientError(_('Homepage is not a valid URL.'),404,'json');
return;
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
// TRANS: Form validation error displayed when trying to register with a too long full name.
$this->clientError(_('Full name is too long (maximum 255 characters).'),404,'json');
return;
} else if (Profile::bioTooLong($bio)) {
// TRANS: Form validation error on registration page when providing too long a bio text.
// TRANS: %d is the maximum number of characters for bio; used for plural.
$this->clientError(sprintf(_m('Bio is too long (maximum %d character).',
'Bio is too long (maximum %d characters).',
Profile::maxBio()),
Profile::maxBio()),404,'json');
return;
} else if (!is_null($location) && mb_strlen($location) > 255) {
// TRANS: Form validation error displayed when trying to register with a too long location.
$this->clientError(_('Location is too long (maximum 255 characters).'),404,'json');
return;
} else if (strlen($password) < 6) {
// TRANS: Form validation error displayed when trying to register with too short a password.
$this->clientError(_('Password must be 6 or more characters.'),404,'json');
return;
} else if ($password != $confirm) {
// TRANS: Form validation error displayed when trying to register with non-matching passwords.
$this->clientError(_('Passwords do not match.'),404,'json');
} else {
// annoy spammers
sleep(7);
if ($user = User::register(array('nickname' => $nickname,
'password' => $password,
'email' => $email,
'fullname' => $fullname,
'homepage' => $homepage,
'bio' => $bio,
'location' => $location,
'code' => $code))) {
if (!$user) {
// TRANS: Form validation error displayed when trying to register with an invalid username or password.
$this->clientError(_('Invalid username or password.'),404,'json');
return;
}
Event::handle('EndRegistrationTry', array($this));
$this->initDocument('json');
$this->showJsonObjects($this->twitterUserArray($user->getProfile()));
$this->endDocument('json');
} else {
// TRANS: Form validation error displayed when trying to register with an invalid username or password.
$this->clientError(_('Invalid username or password.'),404,'json');
}
}
}
}
/**
* Does the given nickname already exist?
*
* Checks a canonical nickname against the database.
*
* @param string $nickname nickname to check
*
* @return boolean true if the nickname already exists
*/
function nicknameExists($nickname)
{
$user = User::staticGet('nickname', $nickname);
return is_object($user);
}
/**
* Does the given email address already exist?
*
* Checks a canonical email address against the database.
*
* @param string $email email address to check
*
* @return boolean true if the address already exists
*/
function emailExists($email)
{
$email = common_canonical_email($email);
if (!$email || strlen($email) == 0) {
return false;
}
$user = User::staticGet('email', $email);
return is_object($user);
}
}

View File

@ -0,0 +1,74 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Check nickname
*
* Returns 1 if nickname is ok, 0 if not
*
* PHP version 5
*
* LICENCE: 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/>.
*
* @category API
* @package StatusNet
* @author Hannes Mannerheim <h@nnesmannerhe.im>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiauth.php';
class ApiCheckNicknameAction extends ApiAction
{
function prepare($args)
{
parent::prepare($args);
return true;
}
function handle($args)
{
parent::handle($args);
$nickname = $this->trimmed('nickname');
if ($this->nicknameExists($nickname)) {
$nickname_ok = 0;
} else if (!User::allowed_nickname($nickname)) {
$nickname_ok = 0; }
else {
$nickname_ok = 1;
}
$this->initDocument('json');
$this->showJsonObjects($nickname_ok);
$this->endDocument('json');
}
function nicknameExists($nickname)
{
$user = User::staticGet('nickname', $nickname);
return is_object($user);
}
}

View File

@ -491,6 +491,14 @@ class Router
$m->connect('api/account/update_background_color.json', $m->connect('api/account/update_background_color.json',
array('action' => 'ApiAccountUpdateBackgroundColor')); array('action' => 'ApiAccountUpdateBackgroundColor'));
$m->connect('api/account/register.json',
array('action' => 'ApiAccountRegister'));
$m->connect('api/check_nickname.json',
array('action' => 'ApiCheckNickname'));
// users // users
$m->connect('api/users/show/:id.:format', $m->connect('api/users/show/:id.:format',

View File

@ -721,6 +721,7 @@ function expand_queet(q) {
q.find('.inline-reply-queetbox').remove(); q.find('.inline-reply-queetbox').remove();
} }
else { else {
rememberMyScrollPos(q.children('.queet'),qid,0);
var collapseTime = 200 + q.find('.stream-item.conversation:not(.hidden-conversation)').length*50; var collapseTime = 200 + q.find('.stream-item.conversation:not(.hidden-conversation)').length*50;
q.find('.expanded-content').slideUp(collapseTime,function(){$(this).remove();}); q.find('.expanded-content').slideUp(collapseTime,function(){$(this).remove();});
q.find('.view-more-container-top').slideUp(collapseTime,function(){$(this).remove();}); q.find('.view-more-container-top').slideUp(collapseTime,function(){$(this).remove();});
@ -806,8 +807,10 @@ function expand_queet(q) {
// show conversation // show conversation
showConversation(qid); showConversation(qid);
// show inline reply form // show inline reply form if logged in
q.find('#q-' + qid).append(replyFormHtml(q,qid)); if(typeof window.loginUsername != 'undefined') {
q.find('#q-' + qid).append(replyFormHtml(q,qid));
}
} }
} }
@ -1270,14 +1273,12 @@ function addToFeed(feed, after, extraClasses) {
// actions only for logged in users // actions only for logged in users
var queetActions = ''; var queetActions = '';
var expandHTML = '';
if(typeof window.loginUsername != 'undefined') { if(typeof window.loginUsername != 'undefined') {
queetActions = '<ul class="queet-actions"><li class="action-reply-container"><a class="with-icn"><span class="icon sm-reply"></span> <b>' + window.sL.replyVerb + '</b></a></li>' + requeetHtml + '<li class="action-fav-container">' + favoriteHtml + '</li></ul>'; queetActions = '<ul class="queet-actions"><li class="action-reply-container"><a class="with-icn"><span class="icon sm-reply"></span> <b>' + window.sL.replyVerb + '</b></a></li>' + requeetHtml + '<li class="action-fav-container">' + favoriteHtml + '</li></ul>';
expandHTML = '<span class="stream-item-expand">' + window.sL.expand + '</span>';
} }
var queetTime = parseTwitterDate(obj.retweeted_status.created_at); var queetTime = parseTwitterDate(obj.retweeted_status.created_at);
var queetHtml = '<div id="stream-item-' + obj.retweeted_status.id + '" class="stream-item ' + extraClassesThisRun + ' ' + requeetedClass + ' ' + favoritedClass + '" data-quitter-id="' + obj.retweeted_status.id + '" data-conversation-id="' + obj.retweeted_status.statusnet_conversation_id + '" data-quitter-id-in-stream="' + obj.id + '" data-in-reply-to-screen-name="' + in_reply_to_screen_name + '" data-in-reply-to-status-id="' + obj.retweeted_status.in_reply_to_status_id + '"><div class="queet" id="q-' + obj.retweeted_status.id + '"><span class="dogear"></span><div class="queet-content"><div class="stream-item-header"><a class="account-group" href="' + obj.retweeted_status.user.statusnet_profile_url + '"><img class="avatar" src="' + obj.retweeted_status.user.profile_image_url + '" /><strong class="name" data-user-id="' + obj.retweeted_status.user.id + '">' + obj.retweeted_status.user.name + '</strong> <span class="screen-name">@' + obj.retweeted_status.user.screen_name + '</span></a><small class="created-at" data-created-at="' + obj.retweeted_status.created_at + '"><a href="' + obj.retweeted_status.uri + '">' + queetTime + '</a></small></div><div class="queet-text">' + $.trim(obj.retweeted_status.statusnet_html) + '</div><div class="stream-item-footer">' + queetActions + '<div class="context" id="requeet-' + obj.id + '"><span class="with-icn"><i class="badge-requeeted"></i><span class="requeet-text"> ' + window.sL.requeetedBy + '<a href="' + obj.user.statusnet_profile_url + '"> <b>' + obj.user.name + '</b></a></span></span></div>' + expandHTML + '</div></div></div></div>'; var queetHtml = '<div id="stream-item-' + obj.retweeted_status.id + '" class="stream-item ' + extraClassesThisRun + ' ' + requeetedClass + ' ' + favoritedClass + '" data-quitter-id="' + obj.retweeted_status.id + '" data-conversation-id="' + obj.retweeted_status.statusnet_conversation_id + '" data-quitter-id-in-stream="' + obj.id + '" data-in-reply-to-screen-name="' + in_reply_to_screen_name + '" data-in-reply-to-status-id="' + obj.retweeted_status.in_reply_to_status_id + '"><div class="queet" id="q-' + obj.retweeted_status.id + '"><span class="dogear"></span><div class="queet-content"><div class="stream-item-header"><a class="account-group" href="' + obj.retweeted_status.user.statusnet_profile_url + '"><img class="avatar" src="' + obj.retweeted_status.user.profile_image_url + '" /><strong class="name" data-user-id="' + obj.retweeted_status.user.id + '">' + obj.retweeted_status.user.name + '</strong> <span class="screen-name">@' + obj.retweeted_status.user.screen_name + '</span></a><small class="created-at" data-created-at="' + obj.retweeted_status.created_at + '"><a href="' + obj.retweeted_status.uri + '">' + queetTime + '</a></small></div><div class="queet-text">' + $.trim(obj.retweeted_status.statusnet_html) + '</div><div class="stream-item-footer">' + queetActions + '<div class="context" id="requeet-' + obj.id + '"><span class="with-icn"><i class="badge-requeeted"></i><span class="requeet-text"> ' + window.sL.requeetedBy + '<a href="' + obj.user.statusnet_profile_url + '"> <b>' + obj.user.name + '</b></a></span></span></div><span class="stream-item-expand">' + window.sL.expand + '</span></div></div></div></div>';
// detect rtl // detect rtl
queetHtml = detectRTL(queetHtml); queetHtml = detectRTL(queetHtml);
@ -1368,14 +1369,12 @@ function addToFeed(feed, after, extraClasses) {
// actions only for logged in users // actions only for logged in users
var queetActions = ''; var queetActions = '';
var expandHTML = '';
if(typeof window.loginUsername != 'undefined') { if(typeof window.loginUsername != 'undefined') {
queetActions = '<ul class="queet-actions"><li class="action-reply-container"><a class="with-icn"><span class="icon sm-reply"></span> <b>' + window.sL.replyVerb + '</b></a></li>' + requeetHtml + '<li class="action-fav-container">' + favoriteHtml + '</li></ul>'; queetActions = '<ul class="queet-actions"><li class="action-reply-container"><a class="with-icn"><span class="icon sm-reply"></span> <b>' + window.sL.replyVerb + '</b></a></li>' + requeetHtml + '<li class="action-fav-container">' + favoriteHtml + '</li></ul>';
expandHTML = '<span class="stream-item-expand">' + window.sL.expand + '</span>';
} }
var queetTime = parseTwitterDate(obj.created_at); var queetTime = parseTwitterDate(obj.created_at);
var queetHtml = '<div id="stream-item-' + obj.id + '" class="stream-item ' + extraClassesThisRun + ' ' + requeetedClass + ' ' + favoritedClass + '" data-quitter-id="' + obj.id + '" data-conversation-id="' + obj.statusnet_conversation_id + '" data-quitter-id-in-stream="' + obj.id + '" data-in-reply-to-screen-name="' + in_reply_to_screen_name + '" data-in-reply-to-status-id="' + obj.in_reply_to_status_id + '"><div class="queet" id="q-' + obj.id + '"><span class="dogear"></span><div class="queet-content"><div class="stream-item-header"><a class="account-group" href="' + obj.user.statusnet_profile_url + '"><img class="avatar" src="' + obj.user.profile_image_url + '" /><strong class="name" data-user-id="' + obj.user.id + '">' + obj.user.name + '</strong> <span class="screen-name">@' + obj.user.screen_name + '</span></a><small class="created-at" data-created-at="' + obj.created_at + '"><a href="' + obj.uri + '">' + queetTime + '</a></small></div><div class="queet-text">' + $.trim(obj.statusnet_html) + '</div><div class="stream-item-footer">' + queetActions + expandHTML + '</div></div></div></div>'; var queetHtml = '<div id="stream-item-' + obj.id + '" class="stream-item ' + extraClassesThisRun + ' ' + requeetedClass + ' ' + favoritedClass + '" data-quitter-id="' + obj.id + '" data-conversation-id="' + obj.statusnet_conversation_id + '" data-quitter-id-in-stream="' + obj.id + '" data-in-reply-to-screen-name="' + in_reply_to_screen_name + '" data-in-reply-to-status-id="' + obj.in_reply_to_status_id + '"><div class="queet" id="q-' + obj.id + '"><span class="dogear"></span><div class="queet-content"><div class="stream-item-header"><a class="account-group" href="' + obj.user.statusnet_profile_url + '"><img class="avatar" src="' + obj.user.profile_image_url + '" /><strong class="name" data-user-id="' + obj.user.id + '">' + obj.user.name + '</strong> <span class="screen-name">@' + obj.user.screen_name + '</span></a><small class="created-at" data-created-at="' + obj.created_at + '"><a href="' + obj.uri + '">' + queetTime + '</a></small></div><div class="queet-text">' + $.trim(obj.statusnet_html) + '</div><div class="stream-item-footer">' + queetActions + '<span class="stream-item-expand">' + window.sL.expand + '</span></div></div></div></div>';
// detect rtl // detect rtl
queetHtml = detectRTL(queetHtml); queetHtml = detectRTL(queetHtml);

View File

@ -126,6 +126,14 @@ window.l.es.settings = 'Configuración';
window.l.es.saveChanges = 'Guardar cambios'; window.l.es.saveChanges = 'Guardar cambios';
window.l.es.linkColor = 'Color del enlace'; window.l.es.linkColor = 'Color del enlace';
window.l.es.backgroundColor = 'Color de fondo'; window.l.es.backgroundColor = 'Color de fondo';
window.l.es.newToQuitter = '¿Eres nuevo en Quitter?';
window.l.es.signUp = 'Regístrate';
window.l.es.signUpFullName = 'Nombre completo';
window.l.es.signUpEmail = 'Correo electrónico';
window.l.es.signUpButtonText = 'Regístrate en Quitter';
window.l.es.welcomeHeading = 'Bienvenido a Quitter.';
window.l.es.welcomeText = 'Somos una <span id="federated-tooltip"><div id="what-is-federation">« Federación » significa que ustedes no debeis tener una cuenta Quitter para seguir sus usuarios, estar seguidos o interaccionar con ellos. ¡Podéis registrar con cualquier servidor StatusNet o <a href="http://www.gnu.org/software/social/">GNU Social</a>, o cualquier servicio utilizando el protocolo <a href="http://www.w3.org/community/ostatus/wiki/Main_Page">OStatus</a>! Incluso, no debéis inscribir vosotros o cualquier cosa puesto que podéis tambien instalar el software GNU Social en vuestro propio servidor. (:</div>federación</span> no comercial de microblogs que, como ustedes, se preocupan de la ética y de la solidaridad, y queremos salir de los servicios centralizados capitalistas. Estamos por aquí desde 2010 y siempre seremos sin ánimo de lucro.';
// french // french
window.l.fr = new Object(); window.l.fr = new Object();
@ -216,6 +224,13 @@ window.l.fr.settings = 'Paramètres';
window.l.fr.saveChanges = 'Sauvegarder les modifications'; window.l.fr.saveChanges = 'Sauvegarder les modifications';
window.l.fr.linkColor = 'Couleur des liens'; window.l.fr.linkColor = 'Couleur des liens';
window.l.fr.backgroundColor = 'Couleur de l\'arrière-plan'; window.l.fr.backgroundColor = 'Couleur de l\'arrière-plan';
window.l.fr.newToQuitter = 'Nouveau sur Quitter ?';
window.l.fr.signUp = 'Inscrivez-vous';
window.l.fr.signUpFullName = 'Nom complet';
window.l.fr.signUpEmail = 'Email';
window.l.fr.signUpButtonText = 'S\'inscrire sur Quitter';
window.l.fr.welcomeHeading = 'Bienvenue sur Quitter.';
window.l.fr.welcomeText = 'Nous sommes une <span id="federated-tooltip"><div id="what-is-federation">La « fédération » signifie que vous n\'êtes pas obligé d\'avoir un compte Quitter pour pouvoir suivre ses utilisateurs, être suivis par eux ou interagir avec eux. Vous pouvez vous enregistrer sur n\'importe quel serveur StatusNet ou <a href="http://www.gnu.org/software/social/">GNU Social</a>, ou n\'importe quel service utilisant le protocole <a href="http://www.w3.org/community/ostatus/wiki/Main_Page">OStatus</a> ! Vous n\'êtes pas même obligés de vous inscrire où que ce soit, puisque vous pouvez aussi installer le programme GNU Social sur votre propre serveur ! :)</div>fédération</span> de microbloggers qui, comme vous, a le souci de l\'éthique, de la solidarité, et de s\'extraire des services centralisés capitalistes. Nous sommes en ligne depuis 2010 et resterons toujours sans but lucratif.';
// deutsch // deutsch
@ -307,7 +322,13 @@ window.l.de.settings = 'Einstellungen';
window.l.de.saveChanges = 'Änderungen speichern'; window.l.de.saveChanges = 'Änderungen speichern';
window.l.de.linkColor = 'Linkfarbe'; window.l.de.linkColor = 'Linkfarbe';
window.l.de.backgroundColor = 'Hintergrundfarbe'; window.l.de.backgroundColor = 'Hintergrundfarbe';
window.l.de.newToQuitter = 'Neu bei Quitter?';
window.l.de.signUp = 'Registriere Dich!';
window.l.de.signUpFullName = 'Vollständiger Name';
window.l.de.signUpEmail = 'E-Mail';
window.l.de.signUpButtonText = 'Registriere Dich bei Quitter!';
window.l.de.welcomeHeading = 'Willkommen bei Quitter!';
window.l.de.welcomeText = 'Wir sind eine Community von Microbloggern, verteilt über einen weltweiten <span id="federated-tooltip"><div id="what-is-federation">"Verbund" bedeutet, dass du nicht selbst einen Quitter-Account brauchst, um mit Quitter-Nutzern zu kommunizieren, ihnen zu folgen oder Follower bei Quitter zu haben. Du kannst dich genauso gut bei einem der anderen <a href="http://www.gnu.org/software/social/">GNU-Social</a>-Server registrieren oder einem anderen Dienst, der das <a href="http://www.w3.org/community/ostatus/wiki/Main_Page">OStatus</a>-Protokoll unterstützt. Du kannst sogar ganz ohne Anmeldung teilnehmen, wenn du dir GNU Social auf deinem eigenen Server installierst.</div>Verbund</span> unabhängiger GNU-Social-Server, auch bekannt als StatusNet. Wir sind genau das Richtige für <strong>Leute wie dich</strong>, denen Ethik und Solidarität etwas bedeuten und die sich nicht mehr an zentralisierten kapitalistischen Diensten beteiligen wollen. Es gibt uns schon seit 2010, und wir werden immer Non-Profit bleiben.';
// english // english
@ -399,6 +420,14 @@ window.l.en.settings = 'Settings';
window.l.en.saveChanges = 'Save changes'; window.l.en.saveChanges = 'Save changes';
window.l.en.linkColor = 'Link color'; window.l.en.linkColor = 'Link color';
window.l.en.backgroundColor = 'Background color'; window.l.en.backgroundColor = 'Background color';
window.l.en.newToQuitter = 'New to Quitter?';
window.l.en.signUp = 'Sign up';
window.l.en.signUpFullName = 'Full name';
window.l.en.signUpEmail = 'Email';
window.l.en.signUpButtonText = 'Sign up for Quitter';
window.l.en.welcomeHeading = 'Welcome to Quitter.';
window.l.en.welcomeText = 'We are a <span id="federated-tooltip"><div id="what-is-federation">"Federation" means that you don\'t have to have a Quitter account to be able to follow, be followed by or interact with Quitter users. You can register on any site that supports the <a href="http://www.w3.org/community/ostatus/wiki/Main_Page">Ostatus</a> protocol! You don\'t even have to join a service try installing the lovely <a href="http://www.gnu.org/software/social/">GNU Social</a> software on your own server! :)</div>federated</span> common, for microbloggers like you who care about ethics and solidarity and want to quit the centralised capitalistic services. We\'ve been around since 2010 and will always be non-profit.';
// svenska // svenska
@ -490,6 +519,14 @@ window.l.sv.settings = 'Inställningar';
window.l.sv.saveChanges = 'Spara ändringarna'; window.l.sv.saveChanges = 'Spara ändringarna';
window.l.sv.linkColor = 'Länkfärg'; window.l.sv.linkColor = 'Länkfärg';
window.l.sv.backgroundColor = 'Bakgrundsfärg'; window.l.sv.backgroundColor = 'Bakgrundsfärg';
window.l.sv.newToQuitter = 'Ny på Quitter?';
window.l.sv.signUp = 'Registrera dig';
window.l.sv.signUpFullName = 'Fullständigt namn';
window.l.sv.signUpEmail = 'E-post';
window.l.sv.signUpButtonText = 'Registrera dig på Quitter';
window.l.sv.welcomeHeading = 'Välkommen till Quitter.';
window.l.sv.welcomeText = 'Vi är en <span id="federated-tooltip"><div id="what-is-federation">"Federering" betyder att du inte behöver ha ett Quitter-konto för att följa, följas av eller prata med quittrare. Du kan registrera dig på vilken sajt som helst som stödjer protokollet <a href="http://www.w3.org/community/ostatus/wiki/Main_Page">Ostatus</a>, eller mikroblogga på en helt egen server, förslagsvis med den fria programvaran <a href="http://www.gnu.org/software/social/">GNU Social</a> (som Quitter bygger på).</div>federerad</span> allmänning, där du som har hoppat av de centraliserade kapitalistiska tjänsterna kan mikroblogga etiskt och solidariskt. Vi har funnits sedan 2010 och sajten drivs helt ideellt.';
@ -582,6 +619,14 @@ window.l.fa.settings = 'تنظیمات';
window.l.fa.saveChanges = 'ذخیره تغییرات'; window.l.fa.saveChanges = 'ذخیره تغییرات';
window.l.fa.linkColor = 'رنگ پیوند'; window.l.fa.linkColor = 'رنگ پیوند';
window.l.fa.backgroundColor = 'رنگ پس‌زمینه'; window.l.fa.backgroundColor = 'رنگ پس‌زمینه';
window.l.fa.newToQuitter = 'تازه واردید؟';
window.l.fa.signUp = 'همین حالا ثبت نام کنید';
window.l.fa.signUpFullName = 'نام و نام‌خانوادگی';
window.l.fa.signUpEmail = 'ایمیل';
window.l.fa.signUpButtonText = 'عضو توییتر شوید';
window.l.fa.welcomeHeading = 'به واگذارنده خوش آمدید.';
window.l.fa.welcomeText = '';
// arabic // arabic
@ -673,6 +718,14 @@ window.l.ar.settings = 'الإعدادات';
window.l.ar.saveChanges = 'حفظ التغييرات'; window.l.ar.saveChanges = 'حفظ التغييرات';
window.l.ar.linkColor = 'لون الرابط'; window.l.ar.linkColor = 'لون الرابط';
window.l.ar.backgroundColor = 'لون الخلفيّة'; window.l.ar.backgroundColor = 'لون الخلفيّة';
window.l.ar.newToQuitter = 'هل أنت جديد على ترك؟';
window.l.ar.signUp = 'سجّل الآن!';
window.l.ar.signUpFullName = 'الاسم الكامل';
window.l.ar.signUpEmail = 'البريد الإلكترونيّ';
window.l.ar.signUpButtonText = 'التسجيل في ترك';
window.l.ar.welcomeHeading = 'مرحبًا بك في ترك.';
window.l.ar.welcomeText = '';
@ -704,11 +757,18 @@ else if(selectedLanguage == 'fa') {
window.siteTitle = $('head title').html(); // remember this for later use window.siteTitle = $('head title').html(); // remember this for later use
// set some static string // set some static string
$('.front-welcome-text h1').html(window.sL.welcomeHeading);
$('.front-welcome-text p').html(window.sL.welcomeText);
$('#username').attr('placeholder',window.sL.loginUsername); $('#username').attr('placeholder',window.sL.loginUsername);
$('#password').attr('placeholder',window.sL.loginPassword); $('#password').attr('placeholder',window.sL.loginPassword);
$('button#submit-login').html(window.sL.loginSignIn); $('button#submit-login').html(window.sL.loginSignIn);
$('#rememberme_label').html(window.sL.loginRememberMe); $('#rememberme_label').html(window.sL.loginRememberMe);
$('#remember-forgot a').html(window.sL.loginForgotPassword); $('#remember-forgot a').html(window.sL.loginForgotPassword);
$('.front-signup h2').html('<strong>' + window.sL.newToQuitter + '</strong> ' + window.sL.signUp);
$('#signup-user-name').attr('placeholder',window.sL.signUpFullName);
$('#signup-user-email').attr('placeholder',window.sL.signUpEmail);
$('#signup-user-password').attr('placeholder',window.sL.loginPassword);
$('.front-signup button.signup-btn').html(window.sL.signUpButtonText);
$('#user-queets .label').html(window.sL.notices); $('#user-queets .label').html(window.sL.notices);
$('#user-following .label').html(window.sL.following); $('#user-following .label').html(window.sL.following);
$('#user-followers .label').html(window.sL.followers); $('#user-followers .label').html(window.sL.followers);

View File

@ -56,6 +56,53 @@ function localStorageIsEnabled() {
} }
/* ·
·
· Checks if register form is valid
·
· @returns true or false
·
· · · · · · · · · */
function validateRegisterForm(o) {
var nickname = o.find('#signup-user-nickname-step2');
var fullname = o.find('#signup-user-name-step2');
var email = o.find('#signup-user-email-step2');
var homepage = o.find('#signup-user-homepage-step2');
var bio = o.find('#signup-user-bio-step2');
var loc = o.find('#signup-user-location-step2');
var password1 = o.find('#signup-user-password1-step2');
var password2 = o.find('#signup-user-password2-step2');
var passwords = o.find('#signup-user-password1-step2,#signup-user-password2-step2');
var allFieldsValid = true;
if(nickname.val().length>1 && /^[a-zA-Z0-9]+$/.test(nickname.val())) {
nickname.removeClass('invalid'); } else { nickname.addClass('invalid'); if(allFieldsValid)allFieldsValid=false; }
if(fullname.val().length < 255) {
fullname.removeClass('invalid'); } else { fullname.addClass('invalid'); if(allFieldsValid)allFieldsValid=false; }
if(/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(email.val())) {
email.removeClass('invalid'); } else { email.addClass('invalid'); if(allFieldsValid)allFieldsValid=false; }
if($.trim(homepage.val()).length==0 || /^(ftp|http|https):\/\/[^ "]+$/.test(homepage.val())) {
homepage.removeClass('invalid'); } else { homepage.addClass('invalid'); if(allFieldsValid)allFieldsValid=false; }
if(bio.val().length < 140) {
bio.removeClass('invalid'); } else { bio.addClass('invalid'); if(allFieldsValid)allFieldsValid=false; }
if(loc.val().length < 255) {
loc.removeClass('invalid'); } else { loc.addClass('invalid'); if(allFieldsValid)allFieldsValid=false; }
if(password1.val().length>5 && password2.val().length>5 && password1.val() == password2.val()) {
passwords.removeClass('invalid'); } else { passwords.addClass('invalid'); if(allFieldsValid)allFieldsValid=false; }
return allFieldsValid;
}
/* · /* ·
· ·

View File

@ -52,9 +52,178 @@ if(window.useHistoryPushState) {
} }
} }
/* · /* ·
· ·
· Preload the default background image and show login box after · fix login and register box to top when they reach top
·
· · · · · · · · · · · · · */
window.loginContentStartPos = $('.front-welcome-text').height()+45;
$(window).scroll(function(e){
if ($(this).scrollTop() > window.loginContentStartPos && $('#login-content').css('position') != 'fixed'){
$('#login-content, .front-signup').not('#popup-signup').css({'position': 'fixed', 'top': '50px'});
}
else if ($(this).scrollTop() < window.loginContentStartPos && $('#login-content').css('position') != 'absolute'){
$('#login-content, .front-signup').not('#popup-signup').css({'position': 'absolute', 'top': 'auto'});
}
});
/* ·
·
· Tooltip to show what federated means
·
· · · · · · · · · · · · · */
$('#federated-tooltip').on('mouseenter',function(){
$('#what-is-federation').fadeIn(100);
});
$('#what-is-federation').on('mouseleave',function(){
$('#what-is-federation').fadeOut(100);
});
/* ·
·
· Register
·
· · · · · · · · · · · · · */
$('.front-signup input, .front-signup button').removeAttr('disabled'); // clear this onload
$('#signup-btn-step1').click(function(){
display_spinner();
$('.front-signup input, .front-signup button').addClass('disabled');
$('.front-signup input, .front-signup button').attr('disabled','disabled');
// 7 s timeout to annoy human spammers
setTimeout(function(){
remove_spinner();
popUpAction('popup-register',window.sL.signUp,'<div id="popup-signup" class="front-signup">' +
'<div class="signup-input-container"><div id="atsign">@</div><input placeholder="Nickname" type="text" autocomplete="off" class="text-input" id="signup-user-nickname-step2"><div class="fieldhelp">a-z0-9</div></div>' +
'<div class="signup-input-container"><input placeholder="' + window.sL.signUpFullName + '" type="text" autocomplete="off" class="text-input" id="signup-user-name-step2" value="' + $('#signup-user-name').val() + '"></div>' +
'<div class="signup-input-container"><input placeholder="' + window.sL.signUpEmail + '" type="text" autocomplete="off" id="signup-user-email-step2" value="' + $('#signup-user-email').val() + '"></div>' +
'<div class="signup-input-container"><input placeholder="Homepage" type="text" autocomplete="off" class="text-input" id="signup-user-homepage-step2"></div>' +
'<div class="signup-input-container"><input placeholder="Bio" type="text" autocomplete="off" class="text-input" id="signup-user-bio-step2"></div>' +
'<div class="signup-input-container"><input placeholder="Location" type="text" autocomplete="off" class="text-input" id="signup-user-location-step2"></div>' +
'<div class="signup-input-container"><input placeholder="' + window.sL.loginPassword + '" type="password" class="text-input" id="signup-user-password1-step2" value="' + $('#signup-user-password').val() + '"><div class="fieldhelp">>5</div></div>' +
'<div class="signup-input-container"><input placeholder="Repeat password" type="password" class="text-input" id="signup-user-password2-step2"></div>' +
'<button id="signup-btn-step2" class="signup-btn disabled" type="submit">' + window.sL.signUpButtonText + '</button>' +
'</div>',false);
// ask api if nickname is ok, if no typing for 1 s
$('#signup-user-nickname-step2').on('keyup',function(){
clearTimeout(window.checkNicknameTimeout);
if($('#signup-user-nickname-step2').val().length>1 && /^[a-zA-Z0-9]+$/.test($('#signup-user-nickname-step2').val())) {
$('#signup-user-nickname-step2').addClass('nickname-taken');
if($('.spinner-wrap').length==0) {
$('#signup-user-nickname-step2').after('<div class="spinner-wrap"><div class="spinner"><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i></div></div>');
}
window.checkNicknameTimeout = setTimeout(function(){
getFromAPI('check_nickname.json?nickname=' + encodeURIComponent($('#signup-user-nickname-step2').val()),function(data){
$('.spinner-wrap').remove();
console.log($('.spinner-wrap').length);
if(data==0) {
$('#signup-user-password2-step2').trigger('keyup'); // revalidates
}
else {
$('#signup-user-nickname-step2').removeClass('nickname-taken');
$('#signup-user-password2-step2').trigger('keyup');
}
});
},1000);
}
else {
$('.spinner-wrap').remove();
}
});
// validate on keyup
$('#popup-register input').on('keyup',function(){
if(validateRegisterForm($('#popup-register'))) {
if(!$('#signup-user-nickname-step2').hasClass('nickname-taken')) {
$('#signup-btn-step2').removeClass('disabled');
}
else {
$('#signup-btn-step2').addClass('disabled');
}
}
else {
$('#signup-btn-step2').addClass('disabled');
}
});
$('#popup-register input').trigger('keyup');
// submit on enter
$('input#signup-user-name-step2,input#signup-user-email-step2,input#signup-user-password1-step2, input#signup-user-password2-step2').keyup(function(e){
if(e.keyCode==13) {
$('#signup-btn-step2').trigger('click');
}
});
$('#signup-btn-step2').click(function(){
$('#popup-register input,#popup-register button').addClass('disabled');
display_spinner();
$.ajax({ url: window.fullUrlToThisQvitterApp + 'API.php',
type: "POST",
data: {
postRequest: 'account/register.json',
nickname: $('#signup-user-nickname-step2').val(),
email: $('#signup-user-email-step2').val(),
fullname: $('#signup-user-name-step2').val(),
homepage: $('#signup-user-homepage-step2').val(),
bio: $('#signup-user-bio-step2').val(),
location: $('#signup-user-location-step2').val(),
password: $('#signup-user-password1-step2').val(),
confirm: $('#signup-user-password2-step2').val(),
username: 'none',
},
dataType:"json",
error: function(data){ console.log('error'); console.log(data); },
success: function(data) {
remove_spinner();
if(typeof data.error == 'undefined') {
$('input#username').val($('#signup-user-nickname-step2').val());
$('input#password').val($('#signup-user-password1-step2').val());
$('input#rememberme').prop('checked', true);
$('#submit-login').trigger('click');
$('#popup-register').remove();
}
else {
alert('Try again! ' + data.error);
$('#popup-register input,#popup-register button').removeClass('disabled');
}
}
});
});
// reactivate register form on popup close
$('#popup-register').on('remove',function(){
$('.front-signup input, .front-signup button').removeAttr('disabled');
$('.front-signup input, .front-signup button').removeClass('disabled');
});
},7000);
});
// submit on enter
$('input#signup-user-name,input#signup-user-email,input#signup-user-password').keyup(function(e){
if(e.keyCode==13) {
$('#signup-btn-step1').trigger('click');
}
});
/* ·
·
· autologin or show welcome screen
· ·
· · · · · · · · · · · · · */ · · · · · · · · · · · · · */
@ -165,14 +334,18 @@ $('#submit-login').click(function () {
// set stream // set stream
window.currentStream = ''; // always reload stream on login window.currentStream = ''; // always reload stream on login
setNewCurrentStream(streamToSet,function(){ setNewCurrentStream(streamToSet,function(){
$('.language-dropdown').css('display','none');
$('.dropdown-menu.quitter-settings li.language').css('display','block');
$('#user-header').animate({opacity:'1'},800); $('#user-header').animate({opacity:'1'},800);
$('#user-body').animate({opacity:'1'},800); $('#user-body').animate({opacity:'1'},800);
$('#user-footer').animate({opacity:'1'},800); $('#user-footer').animate({opacity:'1'},800);
$('.menu-container').animate({opacity:'1'},800); $('.menu-container').animate({opacity:'1'},800);
$('#page-container').animate({opacity:'1'},200); $('#page-container').animate({opacity:'1'},200);
$('.front-welcome-text').slideUp(1000);
$('#settingslink').fadeIn('slow'); $('#settingslink').fadeIn('slow');
$('#search').fadeIn('slow'); $('#search').fadeIn('slow');
$('#login-content').css('display','none'); $('#login-content').css('display','none');
$('.front-signup').css('display','none');
remove_spinner(); remove_spinner();
},true); },true);
@ -279,9 +452,12 @@ function logoutWithoutReload(doShake) {
$('#user-body').animate({opacity:'0'},200); $('#user-body').animate({opacity:'0'},200);
$('#user-footer').animate({opacity:'0'},200); $('#user-footer').animate({opacity:'0'},200);
$('.menu-container').animate({opacity:'0'},200); $('.menu-container').animate({opacity:'0'},200);
$('.language-dropdown').css('display','block');
$('.dropdown-menu.quitter-settings li.language').css('display','none');
$('#settingslink').fadeOut('slow'); $('#settingslink').fadeOut('slow');
$('#search').fadeOut('slow'); $('#search').fadeOut('slow');
$('input#username').focus(); $('input#username').focus();
$('.front-signup').animate({opacity:'1'},200);
if(doShake) { if(doShake) {
$('input#username').css('background-color','pink'); $('input#username').css('background-color','pink');
$('input#password').css('background-color','pink'); $('input#password').css('background-color','pink');
@ -293,6 +469,7 @@ function logoutWithoutReload(doShake) {
$('input#password').animate({backgroundColor:'#fff'},1000); $('input#password').animate({backgroundColor:'#fff'},1000);
}); });
} }
$('.front-welcome-text').fadeIn(3000);
}); });
$('#page-container').animate({opacity:'1'},200); $('#page-container').animate({opacity:'1'},200);
@ -652,7 +829,7 @@ $('body').on('click','a', function(e) {
} }
i++; i++;
}); });
var profileCard = '<div class="profile-card"><div class="profile-header-inner" style="background-image:url(' + data.original_logo + ')"><div class="profile-header-inner-overlay"></div><a class="profile-picture"><img src="' + data.homepage_logo + '" /></a><div class="profile-card-inner"><h1 class="fullname">' + data.fullname + '<span></span></h1><h2 class="username"><span class="screen-name"><a target="_blank" href="' + groupRoot + '/group/' + data.nickname + '">!' + data.nickname + '@' + groupServer + '</a></span></span></h2><div class="bio-container"><p>' + data.description + '</p></div><p class="location-and-url"></span><span class="url"><a href="' + data.homepage + '">' + data.homepage.replace('http://','').replace('https://','') + '</a></span></p></div></div><div class="profile-banner-footer"><ul class="stats"><li><a target="_blank" href="' + groupRoot + '/group/' + data.nickname + '/members" class="member-stats">' + avatars + '</li></ul>' + memberButton + '<div class="clearfix"></div></div></div>'; var profileCard = '<div class="profile-card"><div class="profile-header-inner" style="background-image:url(' + data.original_logo + ')"><div class="profile-header-inner-overlay"></div><a class="profile-picture"><img src="' + data.homepage_logo + '" /></a><div class="profile-card-inner"><h1 class="fullname">' + data.fullname + '<span></span></h1><h2 class="username"><span class="screen-name"><a target="_blank" href="' + groupRoot + '/group/' + data.nickname + '">!' + data.nickname + '@' + groupServer + '</a></span></span></h2><div class="bio-container"><p>' + data.description + '</p></div><p class="location-and-url"></span><span class="url"><a href="' + data.homepage + '">' + data.homepage.replace('http://','').replace('https://','') + '</a></span></p></div></div><div class="profile-banner-footer"><ul class="stats"><li><a target="_blank" href="' + groupRoot + '/group/' + data.nickname + '/members" class="member-stats">' + avatars + '</a></li></ul>' + memberButton + '<div class="clearfix"></div></div></div>';
popUpAction('popup-external-group-profile', '!' + data.nickname + '@' + groupServer,profileCard,false); popUpAction('popup-external-group-profile', '!' + data.nickname + '@' + groupServer,profileCard,false);
remove_spinner(); remove_spinner();
}}); }});
@ -857,8 +1034,7 @@ $('#feed-body').on('click','.queet',function (event) {
&& !$(event.target).is('span.group') && !$(event.target).is('span.group')
&& !$(event.target).is('.longdate') && !$(event.target).is('.longdate')
&& !$(event.target).is('.screen-name') && !$(event.target).is('.screen-name')
&& !$(this).parent('.stream-item').hasClass('user') // not if user stream && !$(this).parent('.stream-item').hasClass('user')) { // not if user stream
&& typeof window.loginUsername != 'undefined') { // not if not logged in
expand_queet($(this).parent()); expand_queet($(this).parent());
} }
}); });