]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Nickname class to encapsulate validation & common regexes for nickname formats.
authorBrion Vibber <brion@pobox.com>
Mon, 29 Nov 2010 22:46:10 +0000 (14:46 -0800)
committerBrion Vibber <brion@pobox.com>
Mon, 29 Nov 2010 22:46:10 +0000 (14:46 -0800)
This provides initial infrastructure for decoupling display names from internal canonical names, but continues to have us storing and using the canonical forms.

It should be/become possible to provide mixed-case and underscore-containing names in links, @-mention, !-group, etc, but we don't store those alternate forms generally.

lib/nickname.php [new file with mode: 0644]
tests/NicknameTest.php

diff --git a/lib/nickname.php b/lib/nickname.php
new file mode 100644 (file)
index 0000000..48269f3
--- /dev/null
@@ -0,0 +1,176 @@
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, 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/>.
+ */
+
+class Nickname
+{
+    /**
+     * Regex fragment for pulling an arbitrarily-formated nickname.
+     *
+     * Not guaranteed to be valid after normalization; run the string through
+     * Nickname::normalize() to get the canonical form, or Nickname::validate()
+     * if you just need to check if it's properly formatted.
+     *
+     * This and CANONICAL_FMT replace the old NICKNAME_FMT, but be aware
+     * that these should not be enclosed in []s.
+     */
+    const DISPLAY_FMT = '[0-9a-zA-Z_]+';
+
+    /**
+     * Regex fragment for checking a canonical nickname.
+     *
+     * Any non-matching string is not a valid canonical/normalized nickname.
+     * Matching strings are valid and canonical form, but may still be
+     * unavailable for registration due to blacklisting et.
+     *
+     * Only the canonical forms should be stored as keys in the database;
+     * there are multiple possible denormalized forms for each valid
+     * canonical-form name.
+     *
+     * This and DISPLAY_FMT replace the old NICKNAME_FMT, but be aware
+     * that these should not be enclosed in []s.
+     */
+    const CANONICAL_FMT = '[0-9a-z]{1,64}';
+
+    /**
+     * Maximum number of characters in a canonical-form nickname.
+     */
+    const MAX_LEN = 64;
+
+    /**
+     * Nice simple check of whether the given string is a valid input nickname,
+     * which can be normalized into an internally canonical form.
+     *
+     * Note that valid nicknames may be in use or reserved.
+     *
+     * @param string $str
+     * @return boolean
+     */
+    public static function validate($str)
+    {
+        try {
+            self::normalize($str);
+            return true;
+        } catch (NicknameException $e) {
+            return false;
+        }
+    }
+
+    /**
+     * Validate an input nickname string, and normalize it to its canonical form.
+     * The canonical form will be returned, or an exception thrown if invalid.
+     *
+     * @param string $str
+     * @return string Normalized canonical form of $str
+     *
+     * @throws NicknameException (base class)
+     * @throws   NicknameInvalidException
+     * @throws   NicknameEmptyException
+     * @throws   NicknameTooLongException
+     */
+    public static function normalize($str)
+    {
+        $str = trim($str);
+        $str = str_replace('_', '', $str);
+        $str = mb_strtolower($str);
+
+        $len = mb_strlen($str);
+        if ($len < 1) {
+            throw new NicknameEmptyException();
+        } else if ($len > self::MAX_LEN) {
+            throw new NicknameTooLongException();
+        }
+        if (!self::isCanonical($str)) {
+            throw new NicknameInvalidException();
+        }
+
+        return $str;
+    }
+
+    /**
+     * Is the given string a valid canonical nickname form?
+     *
+     * @param string $str
+     * @return boolean
+     */
+    public static function isCanonical($str)
+    {
+        return preg_match('/^(?:' . self::CANONICAL_FMT . ')$/', $str);
+    }
+}
+
+class NicknameException extends ClientException
+{
+    function __construct($msg=null, $code=400)
+    {
+        if ($msg === null) {
+            $msg = $this->defaultMessage();
+        }
+        parent::__construct($msg, $code);
+    }
+
+    /**
+     * Default localized message for this type of exception.
+     * @return string
+     */
+    protected function defaultMessage()
+    {
+        return null;
+    }
+}
+
+class NicknameInvalidException extends NicknameException {
+    /**
+     * Default localized message for this type of exception.
+     * @return string
+     */
+    protected function defaultMessage()
+    {
+        // TRANS: Validation error in form for registration, profile and group settings, etc.
+        return _('Nickname must have only lowercase letters and numbers and no spaces.');
+    }
+}
+
+class NicknameEmptyException extends NicknameException
+{
+    /**
+     * Default localized message for this type of exception.
+     * @return string
+     */
+    protected function defaultMessage()
+    {
+        // TRANS: Validation error in form for registration, profile and group settings, etc.
+        return _('Nickname cannot be empty.');
+    }
+}
+
+class NicknameTooLongException extends NicknameInvalidException
+{
+    /**
+     * Default localized message for this type of exception.
+     * @return string
+     */
+    protected function defaultMessage()
+    {
+        // TRANS: Validation error in form for registration, profile and group settings, etc.
+        return sprintf(_m('Nickname cannot be more than %d character long.',
+                          'Nickname cannot be more than %d characters long.',
+                          Nickname::MAX_LEN),
+                       Nickname::MAX_LEN);
+    }
+}
index f1d9808228571feb30ce21b9b70be252e9c6a448..a59cada7ad0ba09db949bca050ae0890d3040d05 100644 (file)
@@ -26,18 +26,18 @@ class NicknameTest extends PHPUnit_Framework_TestCase
         $exception = null;
         $normalized = false;
         try {
-            $normalized = Nickname::normalize($normalized);
+            $normalized = Nickname::normalize($input);
         } catch (NicknameException $e) {
             $exception = $e;
         }
 
         if ($expected === false) {
             if ($expectedException) {
-                $this->assert($exception && $exception instanceof $expectedException,
+                $this->assertTrue($exception && $exception instanceof $expectedException,
                         "invalid input '$input' expected to fail with $expectedException, " .
                         "got " . get_class($exception) . ': ' . $exception->getMessage());
             } else {
-                $this->assert($normalized == false,
+                $this->assertTrue($normalized == false,
                         "invalid input '$input' expected to fail");
             }
         } else {
@@ -47,7 +47,7 @@ class NicknameTest extends PHPUnit_Framework_TestCase
             } else {
                 $msg .= "'$normalized'";
             }
-            $this->assertEquals($expected, $norm, $msg);
+            $this->assertEquals($expected, $normalized, $msg);
         }
     }