Loading...
 

 Note

This page is to document "what Tiki should do". For feature documentation (what Tiki does), please see corresponding page on doc site

blue.box

"Blue.box is an open source GUI for administration and configuration of FreeSWITCH and Asterisk based VoIP system."
http://wiki.2600hz.com/display/bluebox/About+blue.box

blue.box is PHP/MySQL application, like Tiki.

In the context of Tiki Suite, we'll add an integration between Tiki and blue.box. Please note that this is like Tiki's interaction with Kaltura and BigBlueButton (do not get blue.box and BigBlueButton confused as they are distinct FOSS projects), it should be as simple/built-in/native as possible and you do not have to use the full Tiki Suite.

Our existing user base should be able to upgrade to Tiki9, get a

  1. blue.box/FreeSWITCH hosting such as http://www.synapseglobal.com/bluebox_hosting.php
  2. get a phone number (ex.: http://www.synapseglobal.com/voip_termination.php)
  3. configure something in the admin panels and be ready to go.
    • For the desktop app, we'll be focusing on Jitsi support.


Ideally,

  1. From my existing Tiki users/groups, I should be able to set who has what permission level in blue.box.
  2. From Tiki, there would be a one-click login to blue.box (alternatively, users connect to the blue.box interface with the same username/password as Tiki)
  3. Tiki user accounts can get a SIP account in the process (seems to be easy)
  4. Tiki user accounts can get a XMPP account in the process (needs additional work?)


Examples of integration


Questions?

  • How do we keep user data in sync between the two?
    • Tiki is the master and blue.box can't change email and password in blue.box?
    • Sync both ways?
  • blue.box has the following levels: Guest, Restricted User, User, Power User, Restricted Admin, Account Admin, System Admin
    • How do we make this to Tiki groups? tiki_p_bluebox_guest, tiki_p_bluebox_restricted_user, etc.
  • How to configure Jitsi client? Tiki Suite Jitsi blue.box


Testing

Confirmed working 2011-09-19

  1. Create a user at http://bluebox.tikisuite.org/tiki/ (Tiki8)
  2. Login with those credentials at http://bluebox.tikisuite.org/bluebox/
    • user is indeed created with the level "User"
      • This is too high. User should just be able to set personal stuff (my voice mail, etc.)
  3. Login with same credentials with Jitsi (SIP) Tiki Suite Jitsi blue.box

Dogfood use case

  • offer jabber & SIP accounts to all @tiki.org e-mail holders
    • by default, no out-calls, just SIP & Jabber
      • Thus, we need to figure out a scheme for permissions

Integration issues

  • blue.box uses emails, not usernames like Tiki
    • A same e-mail can be used by two different usernames in Tiki
  • When a user calls in, it finds them in tiki and displays their record as a popup
    • Should we have a phone number field type in trackers?

Robert

  • Get commits on blue.box going
  • Get blue.box/FreeSWITCH working with XMPP and jitsi
  • Solve SSO and groups/perms
  • Quick test of PluginJabber which will probably need updating because it's several years old. Let's get something in HTML5/AJAX -> http://www.ohloh.net/tags/ajax/xmpp


Marc and LP discussion

In blue.box, a restriced number of perms:
Regular user can self-configure:
Configure rules for received calls

  • Which email to fwd voice mail attachments
  • Which number to forward to (and the hours)


Admins

  • Can do anything


In blue.box, admins can set-up:
Users can make outgoing calls (and thus can cost $) (which is an attribute to set in blue.box)

Notes about blue.box

  • Groups/permission system in not a default feature, you need to install the plugin (easy to do)

Use cases

Make it easy for any SME to get a blue.box configured for their team.

  • blue.box for standard PBX functionality.
  • Jitsi as soft-phone
  • Tiki as the Intranet (which has all the logins, and sometimes connects to LDAP)

Fred, basic user

  1. Fred logins into Tiki and updates his todo list, wiki pages, etc.
  2. Fred clicks a link in Tiki which sends him to blue.box
  3. Since Tiki and blue-box have been linked/configured, blue.box knows what access level to provide Fred
  4. Since Fred is not an admin, he can't see/change the configurations for other team members.
    • You need to install and configure permission module, which is not part of blue.box core installation.


Fred should be able to configure things like

  • Forwarding voice mail to email address
  • Transfer calls
  • etc.


Fred has documentation on how to configure Jitsi to work with blue.box/FreeSWITCH

Samantha, admin

  • Same as Fred, but can manage all the accounts

Integration code from Robert

Code emailed by Robert Plummer
<?php

ini_set('error_reporting', E_ALL);
ini_set('display_errors', 1);

class Http_Exception extends Exception{
    const NOT_MODIFIED = 304; 
    const BAD_REQUEST = 400; 
    const NOT_FOUND = 404; 
    const NOT_ALOWED = 405; 
    const CONFLICT = 409; 
    const PRECONDITION_FAILED = 412; 
    const INTERNAL_ERROR = 500; 
}

class Http_Stat
{
    private $_status = null;
    private $_type   = null;
    private $_url    = null;
    private $_params = null;
    private $_success = null;
	private $_data = null;
	
    function __construct($status, $type, $url, $params, $success = false, $data = null)
    {
        $this->_status = $status;
        $this->_type   = $type;
        $this->_url    = $url;
        $this->_params = $params;
	$this->_success = $success;
	$this->_data = $data;
    }
    
    function getStatus()
    {
        return $this->_status;
    }
    
    function getType()
    {
        return $this->_type;
    }
    
    function getUrl()
    {
        return $this->_url;
    }
    
    function getParams()
    {
        return $this->_params;
    }
	
	function getSuccess()
	{
		return $this->_success;
	}

	function getData()
	{
		return $this->_data;
	}
}

class Http
{
    private $_host = null;
    private $_port = null;
    private $_user = null;
    private $_pass = null;
    private $_protocol = null;

    const HTTP  = 'http';
    const HTTPS = 'https';
    
    private $_connMultiple = false;
    /**
     * Factory of the class. Lazy connect
     *
     * @param string $host
     * @param integer $port
     * @param string $user
     * @param string $pass
     * @return Http
     */
    static public function connect($host, $port = 80, $protocol = self::HTTP)
    {
        return new self($host, $port, $protocol, false);
    }
    
    /**
     *
     * @return Http
     */
    static public function multiConnect()
    {
        return new self(null, null, null, true);
    }

    private $_append = array();
    public function add($http)
    {
        $this->_append[] = $http;
        return $this;
    }
    
    private $_silentMode = false;
    /**
     *
     * @param bool $mode
     * @return Http
     */
    public function silentMode($mode=true)
    {
        $this->_silentMode = $mode;
        return $this;    
    }
    
    protected function __construct($host, $port, $protocol, $connMultiple)
    {
        $this->_connMultiple = $connMultiple;
        
        $this->_host     = $host;
        $this->_port     = $port;
        $this->_protocol = $protocol;
    }
    
    public function setCredentials($user, $pass)
    {
        $this->_user = $user;
        $this->_pass = $pass;
    }

    const POST   = 'POST';
    const GET    = 'GET';
    const DELETE = 'DELETE';

    private $_requests = array();
    /**
     * @param string $url
     * @param array $params
     * @return Http
     */
    public function post($url, $params=array())
    {
        $this->_requests[] = array(self::POST, $this->_url($url), $params);
        return $this;
    }

    /**
     * @param string $url
     * @param array $params
     * @return Http
     */
    public function get($url, $params=array())
    {
        $this->_requests[] = array(self::GET, $this->_url($url), $params);
        return $this;
    }
    
    /**
     * @param string $url
     * @param array $params
     * @return Http
     */
    public function delete($url, $params=array())
    {
        $this->_requests[] = array(self::DELETE, $this->_url($url), $params);
        return $this;
    }
    
    public function _getRequests()
    {
        return $this->_requests;
    }
    
    /**
     * POST request
     *
     * @param string $url
     * @param array $params
     * @return string
     */
    public function doPost($url, $params=array())
    {
        return $this->_exec(self::POST, $this->_url($url), $params);
    }

    /**
     * GET Request
     *
     * @param string $url
     * @param array $params
     * @return string
     */
    public function doGet($url, $params=array())
    {
        return $this->_exec(self::GET, $this->_url($url), $params);
    }
    
    /**
     * DELETE Request
     *
     * @param string $url
     * @param array $params
     * @return string
     */
    public function doDelete($url, $params=array())
    {
        return $this->_exec(self::DELETE, $this->_url($url), $params);
    }

    private $_headers = array();
    /**
     * setHeaders
     *
     * @param array $headers
     * @return Http
     */
    public function setHeaders($headers)
    {
        $this->_headers = $headers;
        return $this;
    }

    /**
     * Builds absolute url 
     *
     * @param unknown_type $url
     * @return unknown
     */
    private function _url($url=null)
    {
        return "{$this->_protocol}://{$this->_host}:{$this->_port}/{$url}";
    }

    const HTTP_OK = 200;
    const HTTP_CREATED = 201;
    const HTTP_ACEPTED = 202;

    /**
     * Performing the real request
     *
     * @param string $type
     * @param string $url
     * @param array $params
     * @return string
     */
    private function _exec($type, $url, $params = array())
    {
        $headers = $this->_headers;
        $s = curl_init();
        
        if(!is_null($this->_user)){
           curl_setopt($s, CURLOPT_USERPWD, $this->_user.':'.$this->_pass);
        }

        switch ($type) {
            case self::DELETE:
                curl_setopt($s, CURLOPT_URL, $url . '?' . http_build_query($params));
                curl_setopt($s, CURLOPT_CUSTOMREQUEST, self::DELETE);
                break;
            case self::POST:
                curl_setopt($s, CURLOPT_URL, $url);
                curl_setopt($s, CURLOPT_POST, true);
                curl_setopt($s, CURLOPT_POSTFIELDS, $params);
                break;
            case self::GET:
                curl_setopt($s, CURLOPT_URL, $url . '?' . http_build_query($params));
                break;
        }

        curl_setopt($s, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($s, CURLOPT_HTTPHEADER, $headers);
        $_out = curl_exec($s);
        $status = curl_getinfo($s, CURLINFO_HTTP_CODE);
        curl_close($s);
        switch ($status) {
            case self::HTTP_OK:
            case self::HTTP_CREATED:
            case self::HTTP_ACEPTED:
                $out = $_out;
                break;
            default:
                if (!$this->_silentMode) {
                    throw new Http_Exception("http error: {$status}", $status);
                }
        }
        return $out;
    }
    
    public function run()
    {
        if ($this->_connMultiple) {
            return $this->_runMultiple();
        } else {
            return $this->_run();
        }
    }
    
    private function _runMultiple()
    {
        $out= null;
        if (count($this->_append) > 0) {
            $arr = array();
            foreach ($this->_append as $_append) {
                $arr = array_merge($arr, $_append->_getRequests());
            }
            
            $this->_requests = $arr;
            $out = $this->_run();
        }
        return $out;
    }
    
    private function _run()
    {
        $headers = $this->_headers;
        $curly = $result = array();

        $mh = curl_multi_init();
        foreach ($this->_requests as $id => $reg) {
            $curly[$id] = curl_init();
            
            $type   = $reg[0];
            $url    = $reg[1];
            $params = $reg[2];
            
            if(!is_null($this->_user)){
               curl_setopt($curly[$id], CURLOPT_USERPWD, $this->_user.':'.$this->_pass);
            }
            
            switch ($type) {
                case self::DELETE:
                    curl_setopt($curly[$id], CURLOPT_URL, $url . '?' . http_build_query($params));
                    curl_setopt($curly[$id], CURLOPT_CUSTOMREQUEST, self::DELETE);
                    break;
                case self::POST:
                    curl_setopt($curly[$id], CURLOPT_URL, $url);
                    curl_setopt($curly[$id], CURLOPT_POST, true);
                    curl_setopt($curly[$id], CURLOPT_POSTFIELDS, $params);
                    break;
                case self::GET:
                    curl_setopt($curly[$id], CURLOPT_URL, $url . '?' . http_build_query($params));
                    break;
            }
            curl_setopt($curly[$id], CURLOPT_RETURNTRANSFER, true);
            curl_setopt($curly[$id], CURLOPT_HTTPHEADER, $headers);
            
            curl_multi_add_handle($mh, $curly[$id]);
        }
    
        $running = null;
        do {
            curl_multi_exec($mh, $running);
            sleep(0.2);
        } while($running > 0);
    
        foreach($curly as $id => $c) {
            $status = curl_getinfo($c, CURLINFO_HTTP_CODE);
            switch ($status) {
                case self::HTTP_OK:
                case self::HTTP_CREATED:
                case self::HTTP_ACEPTED:
                    $result[$id] = new Http_Stat($status, $type, $url, $params, true, curl_multi_getcontent($c));
                    break;
                default:
                    if (!$this->_silentMode) {
                        $result[$id] = new Http_Stat($status, $type, $url, $params, false);
                    }
            }
            curl_multi_remove_handle($mh, $c);
        }

        curl_multi_close($mh);
        return $result;
    }
}

defined('SYSPATH') OR die('No direct access allowed.');
/**
 * Tiki Auth driver, relies on Doctrine driver
 * Note: this Auth driver does not support roles nor auto-login.
 *
 * $Id: File.php 3917 2009-04-02 03:06:22Z zombor $
 *
 * @package    Auth
 * @author     Robert Plummer
 * @copyright  (c) 2009 Darren Schreiber
 * @license    Mozilla Public License (MPL) v1.1
 */
class Auth_Tiki_Driver extends Auth_Driver
{
    /**
     * VERSION
     */
    const VERSION = '0.1';

    /**
     * Constructor loads the user list into the class.
     */
    public function __construct(array $config, $passwordOrig = '')
    {
        parent::__construct($config);
        
		include_once("Doctrine.php");
        $this->doctrine = new Auth_Doctrine_Driver($config);
		
        if (empty($passwordOrig) && !empty($_REQUEST['login']['password'])) {
	        $passwordOrig = $_REQUEST['login']['password'];
        }
        $this->passwordOrig = $passwordOrig;
    }

    /**
     * Logs a user in.
     *
     * @param   string   username
     * @param   string   password
     * @param   boolean  enable auto-login (not supported)
     * @return  boolean
     */
    public function login($username, $password, $remember, $requirePassword = TRUE)
    {
		$client = Http::connect('bluebox.tikisuite.org');
		$client->setCredentials($username, $this->passwordOrig);
		$status = $client->get('/tiki/tiki-index.php')->run();

		$tikiLogin = FALSE;

		if (isset($status[0])) {
			$tikiLogin = $status[0]->getSuccess();
		}
		
		if ($tikiLogin != TRUE) return $tikiLogin;
		
		//at this point the user exists in tiki
		$userExists = (strlen($this->password($username)) > 0 ? TRUE : FALSE);
		
		if (empty($userExists) && !empty($password)) {
			$emailParts = explode('@', $username);
			
			$userId = $this->createUser($username, $password);
			$deviceId = $this->createDevice($userId, $emailParts[0], $username, $password);
			$numberId = $this->createNumber($deviceId, $emailParts[0]);
		}
		
		return $this->complete_login($username);
		
		//we don't need to verify password here, it was done above from tiki server
        //return $this->doctrine->login($username, $password, $remember, $requirePassword);
    }

    /**
     * Forces a user to be logged in, without specifying a password.
     *
     * @param   mixed    username
     * @return  boolean
     */
    public function force_login($username)
    {
        return $this->doctrine->force_login($username);
    }

    /**
     * Get the stored password for a username.
     *
     * @param   mixed   username
     * @return  string
     */
    public function password($username)
    {
        return $this->doctrine->password($username);
    }

    /**
     * Generate and return a token that allows for resetting of a user's password
     * @param string $username Username of the user to reset
     * @return string Returns a token/hash that should be sent to a user via a confirmed method to allow for reset
     */
    public function resetToken($username)
    {
        return $this->doctrine->resetToken($username);
    }

    /**
     * Force a new password to be recorded, if a password reset token matches the stored token previously generated.
     * @param string $username
     * @param string $token Password token, generated and recorded by resetToken()
     * @param string $newPassword
     * @return boolean True if reset is successful
     */
    public function resetPassword($username, $token, $newPassword)
    {
        return $this->doctrine->resetPassword($username, $token, $newPassword);
    }

    public function getRealIpAddr()
    {
        return $this->doctrine->getRealIpAddr();
    }
	
	private function createUser($username, $password) {
		$user = new User();
		$user['first_name'] = 'Tiki';
		$user['last_name'] = 'Account';
		$user['username'] = $username;
		$user['email_address'] = $username;
		$user['password'] = $password;
		$user['user_type'] = User::TYPE_NORMAL_USER;
		$user['location_id'] = 1;
		$user['account_id'] = 1;
		
		//save user
		Doctrine::getTable('User')->getRecordListener()->get('MultiTenant')->setOption('disabled', TRUE);
		$userId = $user->save();
		Doctrine::getTable('User')->getRecordListener()->get('MultiTenant')->setOption('disabled', FALSE);
		
		return $userId;
	}
	
	private function createDevice($userId, $deviceName, $username, $password) {
		$device = new Device();
		$device['name'] = $deviceName;
		$device['user_id'] = $userId;
		$device['context_id'] = 1;
		$device['account_id'] = 1;
		
		//save device
		Doctrine::getTable('Device')->getRecordListener()->get('MultiTenant')->setOption('disabled', TRUE);
		$deviceId = $device->save();
		Doctrine::getTable('Device')->getRecordListener()->get('MultiTenant')->setOption('disabled', FALSE);
		
		return $deviceId;
	}
	
	private function createNumber($deviceId, $numberName) {
		$number = new Number();
		$number['number'] = $numberName;
		$number['type'] = Number::TYPE_INTERNAL;
		$number['status'] = Number::STATUS_NORMAL;
		$number['location_id'] = 1;
		$number['account_id'] = 1;
		$number['foreign_id'] = $deviceId;
		
		//save number
		Doctrine::getTable('Number')->getRecordListener()->get('MultiTenant')->setOption('disabled', TRUE);
		$numberId = $number->save();
		Doctrine::getTable('Number')->getRecordListener()->get('MultiTenant')->setOption('disabled', FALSE);
		
		return $numberId;
	}
} // End Auth_File_Driver

Related links


alias
Contributors to this page: Marc Laporte .
Page last modified on Saturday 03 November, 2012 19:48:36 UTC by Marc Laporte.

Keywords

The following is a list of keywords that should serve as hubs for navigation within the Tiki development and should correspond to documentation keywords.

Each feature in Tiki has a wiki page which regroups all the bugs, requests for enhancements, etc. It is somewhat a form of wiki-based project management. You can also express your interest in a feature by adding it to your profile. You can also try out the Dynamic filter.

Accessibility (WAI & 508)
Accounting 7.x
Administration
Ajax 2.x
Articles & Submissions
Backlinks
Banner
Batch 6.x
BigBlueButton audio/video/chat/screensharing (5.x)
Blog
Bookmark
Browser Compatibility
Calendar
Category
Chat
Comment
Communication Center
Consistency
Contacts Address book
Contact us
Content template
Contribution 2.x
Cookie
Copyright
Credits 6.x
Custom Home (and Group Home Page)
Database MySQL - MyISAM
Database MySQL - InnoDB
Date and Time
Debugger Console
Directory (of hyperlinks)
Documentation link from Tiki to doc.tiki.org (Help System)
Docs 8.x
DogFood
Draw 7.x
Dynamic Content
Preferences
Dynamic Variable
External Authentication
FAQ
Featured links
Feeds (RSS)
File Gallery
Forum
Friendship Network (Community)
Group
Help
History
Hotword
HTML Page
i18n (Multilingual, l10n, Babelfish)
Image Gallery
Import-Export
Install
Integrator
Interoperability
Inter-User Messages
InterTiki
jQuery
Kaltura video management
Karma
Live Support
Logs (system & action)
Lost edit protection
Mail-in
Map
Menu
Meta Tag
Missing features
Visual Mapping 3.x
Mobile Tiki and Voice Tiki
Mods
Modules
MultiTiki
MyTiki
Newsletter
Notepad
OS independence (Non-Linux, Windows/IIS, Mac, BSD)
Organic Groups (Self-managed Teams)
Payment 5.x
PDF
Performance Speed / Load / Compression / Cache
Permission
Poll
Profiles
Quiz
Rating
Realname
Report
Revision Approval
Score
Search engine optimization (SEO)
Search
Security
Semantic links 3.x
Share
Shopping Cart 5.x
Shoutbox
Site Identity
Slideshow
Smarty Template
Social Networking
Spam protection (Anti-bot CATPCHA)
Spellcheck
Spreadsheet
Staging and Approval
Stats
Survey
Syntax Highlighter (Codemirror)
Tablesorter
Tags 2.x
Task
Tell a Friend, alert + Social Bookmarking
Terms and Conditions
Theme
TikiTests 2.x
Timesheet
Token Access
Toolbar (Quicktags)
Tours
Trackers
TRIM
User Administration
User Files
User Menu
Watch
WebHelp
Webmail and Groupmail
WebServices 3.x
Wiki 3D
Wiki History, page rename, etc
Wiki plugins extends basic syntax
Wiki syntax text area, parser, etc
Wiki structure (book and table of content)
Workspace and perspectives 4.x
WYSIWTSN 4.x
WYSIWYCA
WYSIWYG 2.x
XMLRPC




Useful Tools