Merge branch '0.9.x' into mapstraction

This commit is contained in:
Evan Prodromou 2009-11-19 09:04:56 -05:00
commit b657e49ec7
97 changed files with 19646 additions and 7478 deletions

View File

@ -535,6 +535,28 @@ StartChangePassword: Before changing a password
EndChangePassword: After changing a password
- $user: user
StartSetUser: Before setting the currently logged in user
- $user: user
EndSetUser: After setting the currently logged in user
- $user: user
StartSetApiUser: Before setting the current API user
- $user: user
EndSetApiUser: After setting the current API user
- $user: user
StartHasRole: Before determing if the a profile has a given role
- $profile: profile in question
- $name: name of the role in question
- &$has_role: does this profile have the named role?
EndHasRole: Before determing if the a profile has a given role
- $profile: profile in question
- $name: name of the role in question
- $has_role: does this profile have the named role?
UserDeleteRelated: Specify additional tables to delete entries from when deleting users
- $user: User object
- &$related: array of DB_DataObject class names to delete entries on matching user_id.

View File

@ -117,61 +117,13 @@ class ApiGroupCreateAction extends ApiAuthAction
return;
}
$group = new User_group();
$group->query('BEGIN');
$group->nickname = $this->nickname;
$group->fullname = $this->fullname;
$group->homepage = $this->homepage;
$group->description = $this->description;
$group->location = $this->location;
$group->created = common_sql_now();
$result = $group->insert();
if (!$result) {
common_log_db_error($group, 'INSERT', __FILE__);
$this->serverError(
_('Could not create group.'),
500,
$this->format
);
return;
}
$result = $group->setAliases($this->aliases);
if (!$result) {
$this->serverError(
_('Could not create aliases.'),
500,
$this->format
);
return;
}
$member = new Group_member();
$member->group_id = $group->id;
$member->profile_id = $this->user->id;
$member->is_admin = 1;
$member->created = $group->created;
$result = $member->insert();
if (!$result) {
common_log_db_error($member, 'INSERT', __FILE__);
$this->serverError(
_('Could not set group membership.'),
500,
$this->format
);
return;
}
$group->query('COMMIT');
$group = User_group::register(array('nickname' => $this->nickname,
'fullname' => $this->fullname,
'homepage' => $this->homepage,
'description' => $this->description,
'location' => $this->location,
'aliases' => $this->aliases,
'userid' => $this->user->id));
switch($this->format) {
case 'xml':
$this->showSingleXmlGroup($group);

View File

@ -85,7 +85,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
$this->lat = $this->trimmed('lat');
$this->lon = $this->trimmed('long');
if (empty($this->source) || in_array($source, self::$reserved_sources)) {
if (empty($this->source) || in_array($this->source, self::$reserved_sources)) {
$this->source = 'api';
}

View File

@ -74,7 +74,7 @@ class DesignadminpanelAction extends AdminPanelAction
}
/**
* Show the site admin panel form
* Get the default design and show the design admin panel form
*
* @return void
*/
@ -82,7 +82,6 @@ class DesignadminpanelAction extends AdminPanelAction
function showForm()
{
$this->design = Design::siteDesign();
$form = new DesignAdminPanelForm($this);
$form->show();
return;
@ -101,8 +100,7 @@ class DesignadminpanelAction extends AdminPanelAction
} else if ($this->arg('defaults')) {
$this->restoreDefaults();
} else {
$this->success = false;
$this->message = 'Unexpected form submission.';
$this->clientError(_('Unexpected form submission.'));
}
}
@ -114,7 +112,6 @@ class DesignadminpanelAction extends AdminPanelAction
function saveDesignSettings()
{
// Workaround for PHP returning empty $_POST and $_FILES when POST
// length > post_max_size in php.ini
@ -124,8 +121,7 @@ class DesignadminpanelAction extends AdminPanelAction
) {
$msg = _('The server was unable to handle that much POST ' .
'data (%s bytes) due to its current configuration.');
$this->success = false;
$this->msg = $e->getMessage(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
$this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
return;
}
@ -133,25 +129,30 @@ class DesignadminpanelAction extends AdminPanelAction
$bgimage = $this->saveBackgroundImage();
static $settings = array('theme');
static $settings = array(
'site' => array('theme', 'logo'),
'theme' => array('server', 'dir', 'path'),
'avatar' => array('server', 'dir', 'path'),
'background' => array('server', 'dir', 'path')
);
$values = array();
foreach ($settings as $setting) {
$values[$setting] = $this->trimmed($setting);
foreach ($settings as $section => $parts) {
foreach ($parts as $setting) {
$values[$section][$setting] = $this->trimmed("$section-$setting");
}
}
// This throws an exception on validation errors
try {
$bgcolor = new WebColor($this->trimmed('design_background'));
$ccolor = new WebColor($this->trimmed('design_content'));
$sbcolor = new WebColor($this->trimmed('design_sidebar'));
$tcolor = new WebColor($this->trimmed('design_text'));
$lcolor = new WebColor($this->trimmed('design_links'));
} catch (WebColorException $e) {
$this->success = false;
$this->msg = $e->getMessage();
return;
}
$this->validate($values);
// assert(all values are valid);
$bgcolor = new WebColor($this->trimmed('design_background'));
$ccolor = new WebColor($this->trimmed('design_content'));
$sbcolor = new WebColor($this->trimmed('design_sidebar'));
$tcolor = new WebColor($this->trimmed('design_text'));
$lcolor = new WebColor($this->trimmed('design_links'));
$onoff = $this->arg('design_background-image_onoff');
@ -166,16 +167,14 @@ class DesignadminpanelAction extends AdminPanelAction
$tile = $this->boolean('design_background-image_repeat');
$this->validate($values);
// assert(all values are valid);
$config = new Config();
$config->query('BEGIN');
foreach ($settings as $setting) {
Config::save('site', $setting, $values[$setting]);
foreach ($settings as $section => $parts) {
foreach ($parts as $setting) {
Config::save($section, $setting, $values[$section][$setting]);
}
}
if (isset($bgimage)) {
@ -197,32 +196,6 @@ class DesignadminpanelAction extends AdminPanelAction
$config->query('COMMIT');
return;
}
/**
* Delete a design setting
*
* @return mixed $result false if something didn't work
*/
function deleteSetting($section, $setting)
{
$config = new Config();
$config->section = $section;
$config->setting = $setting;
if ($config->find(true)) {
$result = $config->delete();
if (!$result) {
common_log_db_error($config, 'DELETE', __FILE__);
$this->clientError(_("Unable to delete design setting."));
return null;
}
}
return $result;
}
/**
@ -233,6 +206,7 @@ class DesignadminpanelAction extends AdminPanelAction
function restoreDefaults()
{
$this->deleteSetting('site', 'logo');
$this->deleteSetting('site', 'theme');
$settings = array(
@ -243,6 +217,8 @@ class DesignadminpanelAction extends AdminPanelAction
foreach ($settings as $setting) {
$this->deleteSetting('design', $setting);
}
// XXX: Should we restore the default dir settings, etc.? --Z
}
/**
@ -264,8 +240,7 @@ class DesignadminpanelAction extends AdminPanelAction
$imagefile =
ImageFile::fromUpload('design_background-image_file');
} catch (Exception $e) {
$this->success = false;
$this->msg = $e->getMessage();
$this->clientError('Unable to save background image.');
return;
}
@ -297,8 +272,48 @@ class DesignadminpanelAction extends AdminPanelAction
function validate(&$values)
{
if (!in_array($values['theme'], Theme::listAvailable())) {
$this->clientError(sprintf(_("Theme not available: %s"), $values['theme']));
if (!empty($values['site']['logo']) &&
!Validate::uri($values['site']['logo'], array('allowed_schemes' => array('http', 'https')))) {
$this->clientError(_("Invalid logo URL."));
}
if (!in_array($values['site']['theme'], Theme::listAvailable())) {
$this->clientError(sprintf(_("Theme not available: %s"), $values['site']['theme']));
}
// Make sure the directories are there
if (!empty($values['theme']['dir']) && !is_readable($values['theme']['dir'])) {
$this->clientError(sprintf(_("Theme directory not readable: %s"), $values['theme']['dir']));
}
if (empty($values['avatar']['dir']) || !is_writable($values['avatar']['dir'])) {
$this->clientError(sprintf(_("Avatar directory not writable: %s"), $values['avatar']['dir']));
}
if (empty($values['background']['dir']) || !is_writable($values['background']['dir'])) {
$this->clientError(sprintf(_("Background directory not writable: %s"), $values['background']['dir']));
}
// Do we need to do anything else but validate the
// other fields for length? Design settings are
// validated elsewhere --Z
static $settings = array(
'theme' => array('server', 'path'),
'avatar' => array('server', 'path'),
'background' => array('server', 'path')
);
foreach ($settings as $section => $parts) {
foreach ($parts as $setting) {
if (mb_strlen($values[$section][$setting]) > 255) {
$this->clientError(sprintf(_("Max length for %s %s is 255 characters."),
$section, $setting));
return;
}
}
}
}
@ -332,7 +347,7 @@ class DesignadminpanelAction extends AdminPanelAction
}
class DesignAdminPanelForm extends Form
class DesignAdminPanelForm extends AdminForm
{
/**
@ -393,33 +408,85 @@ class DesignAdminPanelForm extends Form
function formData()
{
$design = $this->out->design;
$this->out->elementStart('fieldset', array('id' => 'settings_design_logo'));
$this->out->element('legend', null, _('Change logo'));
$this->out->elementStart('ul', 'form_data');
$this->li();
$this->input('logo', _('Site logo'), 'Logo for the site (full URL)', 'site');
$this->unli();
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
$this->out->elementStart('fieldset', array('id' => 'settings_design_theme'));
$this->out->element('legend', null, _('Change theme'));
$this->out->elementStart('ul', 'form_data');
$themes = Theme::listAvailable();
asort($themes);
// XXX: listAvailable() can return an empty list if you
// screw up your settings, so just in case:
if (empty($themes)) {
$themes = array('default', 'default');
}
asort($themes);
$themes = array_combine($themes, $themes);
$this->out->elementStart('fieldset', array('id' =>
'settings_design_theme'));
$this->out->element('legend', null, _('Change theme'));
$this->li();
$this->out->dropdown('site-theme', _('Site theme'),
$themes, _('Theme for the site.'),
false, $this->value('theme', 'site'));
$this->unli();
$this->li();
$this->input('server', _('Theme server'), 'Server for themes', 'theme');
$this->unli();
$this->li();
$this->input('path', _('Theme path'), 'Web path to themes', 'theme');
$this->unli();
$this->li();
$this->input('dir', _('Theme directory'), 'Directory where themes are located', 'theme');
$this->unli();
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
$this->out->elementStart('fieldset', array('id' => 'settings_design_avatar'));
$this->out->element('legend', null, _('Avatar Settings'));
$this->out->elementStart('ul', 'form_data');
$this->out->elementStart('li');
$this->out->dropdown('theme', _('Theme'),
$themes, _('Theme for the site.'),
false, $this->value('theme'));
$this->out->elementEnd('li');
$this->li();
$this->input('server', _('Avatar server'), 'Server for avatars', 'avatar');
$this->unli();
$this->li();
$this->input('path', _('Avatar path'), 'Web path to avatars', 'avatar');
$this->unli();
$this->li();
$this->input('dir', _('Avatar directory'), 'Directory where avatars are located', 'avatar');
$this->unli();
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
$design = $this->out->design;
$this->out->elementStart('fieldset', array('id' =>
'settings_design_background-image'));
$this->out->element('legend', null, _('Change background image'));
$this->out->elementStart('ul', 'form_data');
$this->out->elementStart('li');
$this->li();
$this->out->element('label', array('for' => 'design_background-image_file'),
_('Background'));
$this->out->element('input', array('name' => 'design_background-image_file',
@ -432,7 +499,7 @@ class DesignAdminPanelForm extends Form
'type' => 'hidden',
'id' => 'MAX_FILE_SIZE',
'value' => ImageFile::maxFileSizeInt()));
$this->out->elementEnd('li');
$this->unli();
if (!empty($design->backgroundimage)) {
@ -474,27 +541,40 @@ class DesignAdminPanelForm extends Form
'class' => 'radio'),
_('Off'));
$this->out->element('p', 'form_guide', _('Turn background image on or off.'));
$this->out->elementEnd('li');
$this->unli();
$this->out->elementStart('li');
$this->li();
$this->out->checkbox('design_background-image_repeat',
_('Tile background image'),
($design->disposition & BACKGROUND_TILE) ? true : false);
$this->out->elementEnd('li');
$this->unli();
}
$this->li();
$this->input('server', _('Background server'), 'Server for backgrounds', 'background');
$this->unli();
$this->li();
$this->input('path', _('Background path'), 'Web path to backgrounds', 'background');
$this->unli();
$this->li();
$this->input('dir', _('Background directory'), 'Directory where backgrounds are located', 'background');
$this->unli();
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
$this->out->elementStart('fieldset', array('id' => 'settings_design_color'));
$this->out->element('legend', null, _('Change colours'));
$this->out->elementStart('ul', 'form_data');
try {
$bgcolor = new WebColor($design->backgroundcolor);
$this->out->elementStart('li');
$this->li();
$this->out->element('label', array('for' => 'swatch-1'), _('Background'));
$this->out->element('input', array('name' => 'design_background',
'type' => 'text',
@ -503,11 +583,11 @@ class DesignAdminPanelForm extends Form
'maxlength' => '7',
'size' => '7',
'value' => ''));
$this->out->elementEnd('li');
$this->unli();
$ccolor = new WebColor($design->contentcolor);
$this->out->elementStart('li');
$this->li();
$this->out->element('label', array('for' => 'swatch-2'), _('Content'));
$this->out->element('input', array('name' => 'design_content',
'type' => 'text',
@ -516,11 +596,11 @@ class DesignAdminPanelForm extends Form
'maxlength' => '7',
'size' => '7',
'value' => ''));
$this->out->elementEnd('li');
$this->unli();
$sbcolor = new WebColor($design->sidebarcolor);
$this->out->elementStart('li');
$this->li();
$this->out->element('label', array('for' => 'swatch-3'), _('Sidebar'));
$this->out->element('input', array('name' => 'design_sidebar',
'type' => 'text',
@ -529,11 +609,11 @@ class DesignAdminPanelForm extends Form
'maxlength' => '7',
'size' => '7',
'value' => ''));
$this->out->elementEnd('li');
$this->unli();
$tcolor = new WebColor($design->textcolor);
$this->out->elementStart('li');
$this->li();
$this->out->element('label', array('for' => 'swatch-4'), _('Text'));
$this->out->element('input', array('name' => 'design_text',
'type' => 'text',
@ -542,11 +622,11 @@ class DesignAdminPanelForm extends Form
'maxlength' => '7',
'size' => '7',
'value' => ''));
$this->out->elementEnd('li');
$this->unli();
$lcolor = new WebColor($design->linkcolor);
$this->out->elementStart('li');
$this->li();
$this->out->element('label', array('for' => 'swatch-5'), _('Links'));
$this->out->element('input', array('name' => 'design_links',
'type' => 'text',
@ -555,49 +635,16 @@ class DesignAdminPanelForm extends Form
'maxlength' => '7',
'size' => '7',
'value' => ''));
$this->out->elementEnd('li');
$this->unli();
} catch (WebColorException $e) {
common_log(LOG_ERR, 'Bad color values in site design: ' .
$e->getMessage());
}
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
}
/**
* Utility to simplify some of the duplicated code around
* params and settings.
*
* @param string $setting Name of the setting
* @param string $title Title to use for the input
* @param string $instructions Instructions for this field
*
* @return void
*/
function input($setting, $title, $instructions)
{
$this->out->input($setting, $title, $this->value($setting), $instructions);
}
/**
* Utility to simplify getting the posted-or-stored setting value
*
* @param string $setting Name of the setting
*
* @return string param value if posted, or current config value
*/
function value($setting)
{
$value = $this->out->trimmed($setting);
if (empty($value)) {
$value = common_config('site', $setting);
}
return $value;
$this->out->elementEnd('ul');
}
/**
@ -618,5 +665,27 @@ class DesignAdminPanelForm extends Form
'title' => _('Reset back to default')));
$this->out->submit('save', _('Save'), 'submit form_action-secondary',
'save', _('Save design')); }
'save', _('Save design'));
}
/**
* Utility to simplify some of the duplicated code around
* params and settings. Overriding the input() in the base class
* to handle a whole bunch of cases of settings with the same
* name under different sections.
*
* @param string $setting Name of the setting
* @param string $title Title to use for the input
* @param string $instructions Instructions for this field
* @param string $section config section, default = 'site'
*
* @return void
*/
function input($setting, $title, $instructions, $section='site')
{
$this->out->input("$section-$setting", $title, $this->value($setting, $section), $instructions);
}
}

View File

@ -95,7 +95,7 @@ class EmailsettingsAction extends AccountSettingsAction
'class' => 'form_settings',
'action' =>
common_local_url('emailsettings')));
$this->elementStart('fieldset');
$this->elementStart('fieldset', array('id' => 'settings_email_address'));
$this->element('legend', null, _('Address'));
$this->hidden('token', common_session_token());
@ -194,6 +194,7 @@ class EmailsettingsAction extends AccountSettingsAction
$this->elementEnd('ul');
$this->submit('save', _('Save'));
$this->elementEnd('fieldset');
$this->elementEnd('fieldset');
$this->elementEnd('form');
}

View File

@ -133,7 +133,7 @@ class LoginAction extends Action
return;
}
$nickname = common_canonical_nickname($this->trimmed('nickname'));
$nickname = $this->trimmed('nickname');
$password = $this->arg('password');
$user = common_check_user($nickname, $password);
@ -146,7 +146,7 @@ class LoginAction extends Action
// success!
if (!common_set_user($user)) {
$this->serverError(_('Error setting user.'));
$this->serverError(_('Error setting user. You are probably not authorized.'));
return;
}

View File

@ -186,45 +186,13 @@ class NewgroupAction extends Action
assert(!is_null($cur));
$group = new User_group();
$group->query('BEGIN');
$group->nickname = $nickname;
$group->fullname = $fullname;
$group->homepage = $homepage;
$group->description = $description;
$group->location = $location;
$group->created = common_sql_now();
$result = $group->insert();
if (!$result) {
common_log_db_error($group, 'INSERT', __FILE__);
$this->serverError(_('Could not create group.'));
}
$result = $group->setAliases($aliases);
if (!$result) {
$this->serverError(_('Could not create aliases.'));
}
$member = new Group_member();
$member->group_id = $group->id;
$member->profile_id = $cur->id;
$member->is_admin = 1;
$member->created = $group->created;
$result = $member->insert();
if (!$result) {
common_log_db_error($member, 'INSERT', __FILE__);
$this->serverError(_('Could not set group membership.'));
}
$group->query('COMMIT');
$group = User_group::register(array('nickname' => $nickname,
'fullname' => $fullname,
'homepage' => $homepage,
'description' => $description,
'location' => $location,
'aliases' => $aliases,
'userid' => $cur->id));
common_redirect($group->homeUrl(), 303);
}

View File

@ -323,7 +323,7 @@ class ProfilesettingsAction extends AccountSettingsAction
$result = $profile->update($orig_profile);
if (!$result) {
if ($result === false) {
common_log_db_error($profile, 'UPDATE', __FILE__);
$this->serverError(_('Couldn\'t save profile.'));
return;

View File

@ -91,10 +91,12 @@ class SiteadminpanelAction extends AdminPanelAction
function saveSettings()
{
static $settings = array('site' => array('name', 'broughtby', 'broughtbyurl',
'email', 'timezone', 'language'),
'email', 'timezone', 'language',
'ssl', 'sslserver', 'site', 'path',
'textlimit', 'dupelimit', 'locale_path'),
'snapshot' => array('run', 'reporturl', 'frequency'));
static $booleans = array('site' => array('private'));
static $booleans = array('site' => array('private', 'inviteonly', 'closed', 'fancy'));
$values = array();
@ -190,10 +192,42 @@ class SiteadminpanelAction extends AdminPanelAction
$this->clientError(_("Snapshot frequency must be a number."));
}
// Validate SSL setup
if (in_array($values['site']['ssl'], array('sometimes', 'always'))) {
if (empty($values['site']['sslserver'])) {
$this->clientError(_("You must set an SSL sever when enabling SSL."));
}
}
if (mb_strlen($values['site']['sslserver']) > 255) {
$this->clientError(_("Invalid SSL server. Max length is 255 characters."));
}
// Validate text limit
if (!Validate::number($values['site']['textlimit'], array('min' => 140))) {
$this->clientError(_("Minimum text limit is 140c."));
}
// Validate dupe limit
if (!Validate::number($values['site']['dupelimit'], array('min' => 1))) {
$this->clientError(_("Dupe limit must 1 or more seconds."));
}
// Validate locales path
// XXX: What else do we need to validate for lacales path here? --Z
if (!empty($values['site']['locale_path']) && !is_readable($values['site']['locale_path'])) {
$this->clientError(sprintf(_("Locales directory not readable: %s"), $values['site']['locale_path']));
}
}
}
class SiteAdminPanelForm extends Form
class SiteAdminPanelForm extends AdminForm
{
/**
* ID of the form
@ -236,15 +270,19 @@ class SiteAdminPanelForm extends Form
function formData()
{
$this->out->elementStart('fieldset', array('id' => 'settings_admin_general'));
$this->out->element('legend', null, _('General'));
$this->out->elementStart('ul', 'form_data');
$this->li();
$this->input('name', _('Site name'),
_('The name of your site, like "Yourcompany Microblog"'));
$this->unli();
$this->li();
$this->input('broughtby', _('Brought by'),
_('Text used for credits link in footer of each page'));
$this->unli();
$this->li();
$this->input('broughtbyurl', _('Brought by URL'),
_('URL used for credits link in footer of each page'));
@ -252,9 +290,13 @@ class SiteAdminPanelForm extends Form
$this->li();
$this->input('email', _('Email'),
_('contact email address for your site'));
$this->unli();
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
$this->out->elementStart('fieldset', array('id' => 'settings_admin_local'));
$this->out->element('legend', null, _('Local'));
$this->out->elementStart('ul', 'form_data');
$timezones = array();
foreach (DateTimeZone::listIdentifiers() as $k => $v) {
@ -264,100 +306,123 @@ class SiteAdminPanelForm extends Form
asort($timezones);
$this->li();
$this->out->dropdown('timezone', _('Default timezone'),
$timezones, _('Default timezone for the site; usually UTC.'),
true, $this->value('timezone'));
$this->unli();
$this->li();
$this->li();
$this->out->dropdown('language', _('Language'),
get_nice_language_list(), _('Default site language'),
false, $this->value('language'));
$this->unli();
$this->li();
$this->li();
$this->input('locale_path', _('Path to locales'), _('Directory path to locales'));
$this->unli();
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
$this->out->elementStart('fieldset', array('id' => 'settings_admin_urls'));
$this->out->element('legend', null, _('URLs'));
$this->out->elementStart('ul', 'form_data');
$this->li();
$this->input('server', _('Server'), _('Site\'s server hostname.'));
$this->unli();
$this->li();
$this->input('path', _('Path'), _('Site path'));
$this->unli();
$this->li();
$this->out->checkbox('fancy', _('Fancy URLs'),
(bool) $this->value('fancy'),
_('Use fancy (more readable and memorable) URLs?'));
$this->unli();
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
$this->out->elementStart('fieldset', array('id' => 'settings_admin_access'));
$this->out->element('legend', null, _('Access'));
$this->out->elementStart('ul', 'form_data');
$this->li();
$this->out->checkbox('private', _('Private'),
(bool) $this->value('private'),
_('Prohibit anonymous users (not logged in) from viewing site?'));
$this->unli();
$this->li();
$this->out->checkbox('inviteonly', _('Invite only'),
(bool) $this->value('inviteonly'),
_('Make registration invitation only.'));
$this->unli();
$this->li();
$this->out->checkbox('closed', _('Closed'),
(bool) $this->value('closed'),
_('Disable new registrations.'));
$this->unli();
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
$this->out->elementStart('fieldset', array('id' => 'settings_admin_snapshots'));
$this->out->element('legend', null, _('Snapshots'));
$this->out->elementStart('ul', 'form_data');
$this->li();
$snapshot = array('web' => _('Randomly during Web hit'),
'cron' => _('In a scheduled job'),
'never' => _('Never'));
$this->out->dropdown('run', _('Data snapshots'),
$snapshot, _('When to send statistical data to status.net servers'),
false, $this->value('run', 'snapshot'));
$this->unli();
$this->li();
$this->li();
$this->input('frequency', _('Frequency'),
_('Snapshots will be sent once every N Web hits'),
'snapshot');
$this->unli();
$this->li();
$this->input('reporturl', _('Report URL'),
_('Snapshots will be sent to this URL'),
'snapshot');
$this->unli();
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
$this->out->elementStart('fieldset', array('id' => 'settings_admin_ssl'));
$this->out->element('legend', null, _('SSL'));
$this->out->elementStart('ul', 'form_data');
$this->li();
$ssl = array('never' => _('Never'),
'sometimes' => _('Sometimes'),
'always' => _('Always'));
$this->out->dropdown('ssl', _('Use SSL'),
$ssl, _('When to use SSL'),
false, $this->value('ssl', 'site'));
$this->unli();
$this->li();
$this->input('sslserver', _('SSL Server'),
_('Server to direct SSL requests to'));
$this->unli();
$this->out->elementEnd('ul');
}
$this->out->elementEnd('fieldset');
/**
* Utility to simplify some of the duplicated code around
* params and settings.
*
* @param string $setting Name of the setting
* @param string $title Title to use for the input
* @param string $instructions Instructions for this field
* @param string $section config section, default = 'site'
*
* @return void
*/
$this->out->elementStart('fieldset', array('id' => 'settings_admin_limits'));
$this->out->element('legend', null, _('Limits'));
$this->out->elementStart('ul', 'form_data');
$this->li();
$this->input('textlimit', _('Text limit'), _('Maximum number of characters for notices.'));
$this->unli();
function input($setting, $title, $instructions, $section='site')
{
$this->out->input($setting, $title, $this->value($setting, $section), $instructions);
}
/**
* Utility to simplify getting the posted-or-stored setting value
*
* @param string $setting Name of the setting
* @param string $main configuration section, default = 'site'
*
* @return string param value if posted, or current config value
*/
function value($setting, $main='site')
{
$value = $this->out->trimmed($setting);
if (empty($value)) {
$value = common_config($main, $setting);
}
return $value;
}
function li()
{
$this->out->elementStart('li');
}
function unli()
{
$this->out->elementEnd('li');
$this->li();
$this->input('dupelimit', _('Dupe limit'), _('How long users must wait (in seconds) to post the same thing again.'));
$this->unli();
$this->out->elementEnd('ul');
$this->out->elementEnd('fieldset');
}
/**

View File

@ -594,9 +594,14 @@ class Profile extends Memcached_DataObject
function hasRole($name)
{
$role = Profile_role::pkeyGet(array('profile_id' => $this->id,
'role' => $name));
return (!empty($role));
$has_role = false;
if (Event::handle('StartHasRole', array($this, $name, &$has_role))) {
$role = Profile_role::pkeyGet(array('profile_id' => $this->id,
'role' => $name));
$has_role = !empty($role);
Event::handle('EndHasRole', array($this, $name, $has_role));
}
return $has_role;
}
function grantRole($name)

View File

@ -354,4 +354,66 @@ class User_group extends Memcached_DataObject
return $xs->getString();
}
static function register($fields) {
// MAGICALLY put fields into current scope
extract($fields);
$group = new User_group();
$group->query('BEGIN');
$group->nickname = $nickname;
$group->fullname = $fullname;
$group->homepage = $homepage;
$group->description = $description;
$group->location = $location;
$group->created = common_sql_now();
$result = $group->insert();
if (!$result) {
common_log_db_error($group, 'INSERT', __FILE__);
$this->serverError(
_('Could not create group.'),
500,
$this->format
);
return;
}
$result = $group->setAliases($aliases);
if (!$result) {
$this->serverError(
_('Could not create aliases.'),
500,
$this->format
);
return;
}
$member = new Group_member();
$member->group_id = $group->id;
$member->profile_id = $userid;
$member->is_admin = 1;
$member->created = $group->created;
$result = $member->insert();
if (!$result) {
common_log_db_error($member, 'INSERT', __FILE__);
$this->serverError(
_('Could not set group membership.'),
500,
$this->format
);
return;
}
$group->query('COMMIT');
return $group;
}
}

View File

@ -30,6 +30,7 @@ VALUES
('mbpidgin','mbpidgin','http://code.google.com/p/microblog-purple/', now()),
('Mobidentica', 'Mobidentica', 'http://www.substanceofcode.com/software/mobidentica/', now()),
('moconica','Moconica','http://moconica.com/', now()),
('mustard', 'MuSTArDroid', 'https://launchpad.net/mustardroid', now()),
('nambu','Nambu','http://www.nambu.com/', now()),
('peoplebrowsr', 'PeopleBrowsr', 'http://www.peoplebrowsr.com/', now()),
('Pikchur','Pikchur','http://www.pikchur.com/', now()),

86
lib/adminform.php Normal file
View File

@ -0,0 +1,86 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Base class for administrative forms
*
* 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 Widget
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc.
* @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') && !defined('LACONICA')) {
exit(1);
}
/**
* Base class for Administrative forms
*
* Just a place holder for some utility methods to simply some
* repetitive form building code
*
* @category Widget
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*
* @see Form
*/
class AdminForm extends Form
{
/**
* Utility to simplify some of the duplicated code around
* params and settings.
*
* @param string $setting Name of the setting
* @param string $title Title to use for the input
* @param string $instructions Instructions for this field
* @param string $section config section, default = 'site'
*
* @return void
*/
function input($setting, $title, $instructions, $section='site')
{
$this->out->input($setting, $title, $this->value($setting, $section), $instructions);
}
/**
* Utility to simplify getting the posted-or-stored setting value
*
* @param string $setting Name of the setting
* @param string $main configuration section, default = 'site'
*
* @return string param value if posted, or current config value
*/
function value($setting, $main='site')
{
$value = $this->out->trimmed($setting);
if (empty($value)) {
$value = common_config($main, $setting);
}
return $value;
}
}

View File

@ -224,6 +224,33 @@ class AdminPanelAction extends Action
$this->clientError(_('saveSettings() not implemented.'));
return;
}
/**
* Delete a design setting
*
* // XXX: Maybe this should go in Design? --Z
*
* @return mixed $result false if something didn't work
*/
function deleteSetting($section, $setting)
{
$config = new Config();
$config->section = $section;
$config->setting = $setting;
if ($config->find(true)) {
$result = $config->delete();
if (!$result) {
common_log_db_error($config, 'DELETE', __FILE__);
$this->clientError(_("Unable to delete design setting."));
return null;
}
}
return $result;
}
}
/**

View File

@ -110,7 +110,11 @@ class ApiAuthAction extends ApiAction
} else {
$nickname = $this->auth_user;
$password = $this->auth_pw;
$this->auth_user = common_check_user($nickname, $password);
$user = common_check_user($nickname, $password);
if (Event::handle('StartSetApiUser', array(&$user))) {
$this->auth_user = $user;
Event::handle('EndSetApiUser', array($user));
}
if (empty($this->auth_user)) {

View File

@ -59,10 +59,6 @@ require_once('PEAR.php');
require_once('DB/DataObject.php');
require_once('DB/DataObject/Cast.php'); # for dates
if (!function_exists('gettext')) {
require_once("php-gettext/gettext.inc");
}
require_once(INSTALLDIR.'/lib/language.php');
// This gets included before the config file, so that admin code and plugins

View File

@ -181,4 +181,14 @@ class Form extends Widget
{
return 'form';
}
function li()
{
$this->out->elementStart('li');
}
function unli()
{
$this->out->elementEnd('li');
}
}

View File

@ -32,6 +32,63 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
if (!function_exists('gettext')) {
require_once("php-gettext/gettext.inc");
}
if (!function_exists('pgettext')) {
/**
* Context-aware gettext wrapper; use when messages in different contexts
* won't be distinguished from the English source but need different translations.
* The context string will appear as msgctxt in the .po files.
*
* Not currently exposed in PHP's gettext module; implemented to be compat
* with gettext.h's macros.
*
* @param string $context context identifier, should be some key like "menu|file"
* @param string $msgid English source text
* @return string original or translated message
*/
function pgettext($context, $msg)
{
$msgid = $context . "\004" . $msg;
$out = dcgettext(textdomain(NULL), $msgid, LC_MESSAGES);
if ($out == $msgid) {
return $msg;
} else {
return $out;
}
}
}
if (!function_exists('npgettext')) {
/**
* Context-aware ngettext wrapper; use when messages in different contexts
* won't be distinguished from the English source but need different translations.
* The context string will appear as msgctxt in the .po files.
*
* Not currently exposed in PHP's gettext module; implemented to be compat
* with gettext.h's macros.
*
* @param string $context context identifier, should be some key like "menu|file"
* @param string $msg singular English source text
* @param string $plural plural English source text
* @param int $n number of items to control plural selection
* @return string original or translated message
*/
function npgettext($context, $msg, $plural, $n)
{
$msgid = $context . "\004" . $msg;
$out = dcngettext(textdomain(NULL), $msgid, $plural, $n, LC_MESSAGES);
if ($out == $msgid) {
return $msg;
} else {
return $out;
}
}
}
/**
* Content negotiation for language codes
*

View File

@ -77,6 +77,6 @@ class UnblockForm extends ProfileActionForm
function description()
{
return _('Unlock this user');
return _('Unblock this user');
}
}

View File

@ -196,10 +196,15 @@ function common_set_user($user)
}
if ($user) {
common_ensure_session();
$_SESSION['userid'] = $user->id;
$_cur = $user;
return $_cur;
if (Event::handle('StartSetUser', array(&$user))) {
if($user){
common_ensure_session();
$_SESSION['userid'] = $user->id;
$_cur = $user;
Event::handle('EndSetUser', array($user));
return $_cur;
}
}
}
return false;
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
/**
* StatusNet, the distributed open-source microblogging tool
*
* Superclass for plugins that do authentication and/or authorization
* Superclass for plugins that do authentication
*
* PHP version 5
*

View File

@ -0,0 +1,108 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Superclass for plugins that do authorization
*
* 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 Plugin
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @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') && !defined('LACONICA')) {
exit(1);
}
/**
* Superclass for plugins that do authorization
*
* @category Plugin
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
abstract class AuthorizationPlugin extends Plugin
{
//is this plugin authoritative for authorization?
public $authoritative = false;
//------------Auth plugin should implement some (or all) of these methods------------\\
/**
* Is a user allowed to log in?
* @param user
* @return boolean true if the user is allowed to login, false if explicitly not allowed to login, null if we don't explicitly allow or deny login
*/
function loginAllowed($user) {
return null;
}
/**
* Does a profile grant the user a named role?
* @param profile
* @return boolean true if the profile has the role, false if not
*/
function hasRole($profile, $name) {
return false;
}
//------------Below are the methods that connect StatusNet to the implementing Auth plugin------------\\
function onInitializePlugin(){
}
function onStartSetUser(&$user) {
$loginAllowed = $this->loginAllowed($user);
if($loginAllowed === true){
return;
}else if($loginAllowed === false){
$user = null;
return false;
}else{
if($this->authoritative) {
$user = null;
return false;
}else{
return;
}
}
}
function onStartSetApiUser(&$user) {
return $this->onStartSetUser(&$user);
}
function onStartHasRole($profile, $name, &$has_role) {
if($this->hasRole($profile, $name)){
$has_role = true;
return false;
}else{
if($this->authoritative) {
$has_role = false;
return false;
}else{
return;
}
}
}
}

View File

@ -2,7 +2,7 @@
/**
* StatusNet, the distributed open-source microblogging tool
*
* Plugin to enable LDAP Authentication and Authorization
* Plugin to enable LDAP Authentication
*
* PHP version 5
*
@ -63,6 +63,9 @@ class LdapAuthenticationPlugin extends AuthenticationPlugin
if(!isset($this->attributes['username'])){
throw new Exception("must specify a username attribute");
}
if($this->password_changeable && (! isset($this->attributes['password']) || !isset($this->password_encoding))){
throw new Exception("if password_changeable is set, the password attribute and password_encoding must also be specified");
}
}
//---interface implementation---//
@ -156,20 +159,21 @@ class LdapAuthenticationPlugin extends AuthenticationPlugin
}
function ldap_get_connection($config = null){
if($config == null){
$config = $this->ldap_get_config();
if($config == null && isset($this->default_ldap)){
return $this->default_ldap;
}
//cannot use Net_LDAP2::connect() as StatusNet uses
//PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'handleError');
//PEAR handling can be overridden on instance objects, so we do that.
$ldap = new Net_LDAP2($config);
$ldap = new Net_LDAP2(isset($config)?$config:$this->ldap_get_config());
$ldap->setErrorHandling(PEAR_ERROR_RETURN);
$err=$ldap->bind();
if (Net_LDAP2::isError($err)) {
common_log(LOG_WARNING, 'Could not connect to LDAP server: '.$err->getMessage());
return false;
}
if($config == null) $this->default_ldap=$ldap;
return $ldap;
}
@ -186,7 +190,6 @@ class LdapAuthenticationPlugin extends AuthenticationPlugin
}
$filter = Net_LDAP2_Filter::create($this->attributes['username'], 'equals', $username);
$options = array(
'scope' => 'sub',
'attributes' => $attributes
);
$search = $ldap->search(null,$filter,$options);

View File

@ -0,0 +1,211 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Plugin to enable LDAP Authorization
*
* 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 Plugin
* @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
* @copyright 2009 Craig Andrews http://candrews.integralblue.com
* @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') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/plugins/Authorization/AuthorizationPlugin.php';
require_once 'Net/LDAP2.php';
class LdapAuthorizationPlugin extends AuthorizationPlugin
{
public $host=null;
public $port=null;
public $version=null;
public $starttls=null;
public $binddn=null;
public $bindpw=null;
public $basedn=null;
public $options=null;
public $filter=null;
public $scope=null;
public $provider_name = null;
public $uniqueMember_attribute = null;
public $roles_to_groups = array();
public $login_group = null;
public $attributes = array();
function onInitializePlugin(){
parent::onInitializePlugin();
if(!isset($this->host)){
throw new Exception("must specify a host");
}
if(!isset($this->basedn)){
throw new Exception("must specify a basedn");
}
if(!isset($this->provider_name)){
throw new Exception("provider_name must be set. Use the provider_name from the LDAP Authentication plugin.");
}
if(!isset($this->uniqueMember_attribute)){
throw new Exception("uniqueMember_attribute must be set.");
}
if(!isset($this->attributes['username'])){
throw new Exception("username attribute must be set.");
}
}
//---interface implementation---//
function loginAllowed($user) {
$user_username = new User_username();
$user_username->user_id=$user->id;
$user_username->provider_name=$this->provider_name;
if($user_username->find() && $user_username->fetch()){
$entry = $this->ldap_get_user($user_username->username);
if($entry){
if(isset($this->login_group)){
if(is_array($this->login_group)){
foreach($this->login_group as $group){
if($this->ldap_is_dn_member_of_group($entry->dn(),$group)){
return true;
}
}
}else{
if($this->ldap_is_dn_member_of_group($entry->dn(),$this->login_group)){
return true;
}
}
return null;
}else{
//if a user exists, we can assume he's allowed to login
return true;
}
}else{
return null;
}
}else{
return null;
}
}
function hasRole($profile, $name) {
$user_username = new User_username();
$user_username->user_id=$profile->id;
$user_username->provider_name=$this->provider_name;
if($user_username->find() && $user_username->fetch()){
$entry = $this->ldap_get_user($user_username->username);
if($entry){
if(isset($this->roles_to_groups[$name])){
if(is_array($this->roles_to_groups[$name])){
foreach($this->roles_to_groups[$name] as $group){
if($this->ldap_is_dn_member_of_group($entry->dn(),$group)){
return true;
}
}
}else{
if($this->ldap_is_dn_member_of_group($entry->dn(),$this->roles_to_groups[$name])){
return true;
}
}
}
}
}
return false;
}
function ldap_is_dn_member_of_group($userDn, $groupDn)
{
$ldap = $this->ldap_get_connection();
$link = $ldap->getLink();
$r = ldap_compare($link, $groupDn, $this->uniqueMember_attribute, $userDn);
if ($r === true){
return true;
}else if($r === false){
return false;
}else{
common_log(LOG_ERR, ldap_error($r));
return false;
}
}
function ldap_get_config(){
$config = array();
$keys = array('host','port','version','starttls','binddn','bindpw','basedn','options','filter','scope');
foreach($keys as $key){
$value = $this->$key;
if($value!==null){
$config[$key]=$value;
}
}
return $config;
}
//-----the below function were copied from LDAPAuthenticationPlugin. They will be moved to a utility class soon.----\\
function ldap_get_connection($config = null){
if($config == null && isset($this->default_ldap)){
return $this->default_ldap;
}
//cannot use Net_LDAP2::connect() as StatusNet uses
//PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'handleError');
//PEAR handling can be overridden on instance objects, so we do that.
$ldap = new Net_LDAP2(isset($config)?$config:$this->ldap_get_config());
$ldap->setErrorHandling(PEAR_ERROR_RETURN);
$err=$ldap->bind();
if (Net_LDAP2::isError($err)) {
common_log(LOG_WARNING, 'Could not connect to LDAP server: '.$err->getMessage());
return false;
}
if($config == null) $this->default_ldap=$ldap;
return $ldap;
}
/**
* get an LDAP entry for a user with a given username
*
* @param string $username
* $param array $attributes LDAP attributes to retrieve
* @return string DN
*/
function ldap_get_user($username,$attributes=array(),$ldap=null){
if($ldap==null) {
$ldap = $this->ldap_get_connection();
}
$filter = Net_LDAP2_Filter::create($this->attributes['username'], 'equals', $username);
$options = array(
'attributes' => $attributes
);
$search = $ldap->search(null,$filter,$options);
if (PEAR::isError($search)) {
common_log(LOG_WARNING, 'Error while getting DN for user: '.$search->getMessage());
return false;
}
if($search->count()==0){
return false;
}else if($search->count()==1){
$entry = $search->shiftEntry();
return $entry;
}else{
common_log(LOG_WARNING, 'Found ' . $search->count() . ' ldap user with the username: ' . $username);
return false;
}
}
}

View File

@ -0,0 +1,91 @@
The LDAP Authorization plugin allows for StatusNet to handle authorization
through LDAP.
Installation
============
add "addPlugin('ldapAuthorization',
array('setting'=>'value', 'setting2'=>'value2', ...);"
to the bottom of your config.php
You *cannot* use this plugin without the LDAP Authentication plugin
Settings
========
provider_name*: name of the LDAP authentication provider that this plugin works with.
authoritative (false): should this plugin be authoritative for
authorization?
uniqueMember_attribute ('uniqueMember')*: the attribute of a group
that lists the DNs of its members
roles_to_groups: array that maps StatusNet roles to LDAP groups
some StatusNet roles are: moderator, administrator, sandboxed, silenced
login_group: if this is set to a group DN, only members of that group will be
allowed to login
The below settings must be exact copies of the settings used for the
corresponding LDAP Authentication plugin.
host*: LDAP server name to connect to. You can provide several hosts in an
array in which case the hosts are tried from left to right.
See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
port: Port on the server.
See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
version: LDAP version.
See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
starttls: TLS is started after connecting.
See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
binddn: The distinguished name to bind as (username).
See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
bindpw: Password for the binddn.
See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
basedn*: LDAP base name (root directory).
See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
options: See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
filter: Default search filter.
See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
scope: Default search scope.
See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
attributes: an array that relates StatusNet user attributes to LDAP ones
username*: LDAP attribute value entered when authenticating to StatusNet
* required
default values are in (parenthesis)
Example
=======
Here's an example of an LDAP plugin configuration that connects to
Microsoft Active Directory.
addPlugin('ldapAuthentication', array(
'provider_name'=>'Example',
'authoritative'=>true,
'autoregistration'=>true,
'binddn'=>'username',
'bindpw'=>'password',
'basedn'=>'OU=Users,OU=StatusNet,OU=US,DC=americas,DC=global,DC=loc',
'host'=>array('server1', 'server2'),
'password_encoding'=>'ad',
'attributes'=>array(
'username'=>'sAMAccountName',
'nickname'=>'sAMAccountName',
'email'=>'mail',
'fullname'=>'displayName',
'password'=>'unicodePwd')
));
addPlugin('ldapAuthorization', array(
'provider_name'=>'Example',
'authoritative'=>false,
'uniqueMember_attribute'=>'member',
'roles_to_groups'=> array(
'moderator'=>'CN=SN-Moderators,OU=Users,OU=StatusNet,OU=US,DC=americas,DC=global,DC=loc',
'administrator'=> array('CN=System-Adminstrators,OU=Users,OU=StatusNet,OU=US,DC=americas,DC=global,DC=loc',
'CN=SN-Administrators,OU=Users,OU=StatusNet,OU=US,DC=americas,DC=global,DC=loc')
),
'binddn'=>'username',
'bindpw'=>'password',
'basedn'=>'OU=Users,OU=StatusNet,OU=US,DC=americas,DC=global,DC=loc',
'host'=>array('server1', 'server2'),
'attributes'=>array(
'username'=>'sAMAccountName')
));

View File

@ -101,8 +101,8 @@ class RealtimePlugin extends Plugin
$realtimeUI = ' RealtimeUpdate.initPopupWindow();';
}
else {
$iconurl = common_path('plugins/Realtime/icon_external.gif');
$realtimeUI = ' RealtimeUpdate.addPopup("'.$url.'", "'.$timeline.'", "'. $iconurl .'");';
$pluginPath = common_path('plugins/Realtime/');
$realtimeUI = ' RealtimeUpdate.initActions("'.$url.'", "'.$timeline.'", "'. $pluginPath .'");';
}
$action->elementStart('script', array('type' => 'text/javascript'));
@ -118,6 +118,13 @@ class RealtimePlugin extends Plugin
return true;
}
function onEndShowStatusNetStyles($action)
{
$action->cssLink(common_path('plugins/Realtime/realtimeupdate.css'),
null, 'screen, projection, tv');
return true;
}
function onEndNoticeSave($notice)
{
$paths = array();

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 B

View File

@ -0,0 +1,49 @@
#notices_primary {
position:relative;
}
#realtime_actions {
position: absolute;
top: -20px;
right: 0;
margin: 0 0 11px 0;
}
#realtime_actions li {
margin-left: 18px;
list-style-type: none;
float: left;
}
#realtime_actions button {
width: 16px;
height: 16px;
display: block;
border: none;
cursor: pointer;
text-indent: -9999px;
float: left;
}
#realtime_play {
background: url(icon_play.gif) no-repeat 47% 47%;
margin-left: 4px;
}
#realtime_pause {
background: url(icon_pause.gif) no-repeat 47% 47%;
}
#realtime_popup {
background: url(icon_external.gif) no-repeat 0 30%;
}
#queued_counter {
float:left;
line-height:1.2;
}
#showstream #notices_primary {
margin-top: 18px;
}

View File

@ -36,6 +36,9 @@ RealtimeUpdate = {
_updatecounter: 0,
_maxnotices: 50,
_windowhasfocus: true,
_documenttitle: '',
_paused:false,
_queuedNotices:[],
init: function(userid, replyurl, favorurl, deleteurl)
{
@ -44,7 +47,7 @@ RealtimeUpdate = {
RealtimeUpdate._favorurl = favorurl;
RealtimeUpdate._deleteurl = deleteurl;
DT = document.title;
RealtimeUpdate._documenttitle = document.title;
$(window).bind('focus', function(){ RealtimeUpdate._windowhasfocus = true; });
@ -54,7 +57,7 @@ RealtimeUpdate = {
$('#notices_primary .notice:first').addClass('mark-top');
RealtimeUpdate._updatecounter = 0;
document.title = DT;
document.title = RealtimeUpdate._documenttitle;
RealtimeUpdate._windowhasfocus = false;
return false;
@ -63,31 +66,48 @@ RealtimeUpdate = {
receive: function(data)
{
id = data.id;
if (RealtimeUpdate._paused === false) {
RealtimeUpdate.purgeLastNoticeItem();
// Don't add it if it already exists
if ($("#notice-"+id).length > 0) {
return;
RealtimeUpdate.insertNoticeItem(data);
}
else {
RealtimeUpdate._queuedNotices.push(data);
RealtimeUpdate.updateQueuedCounter();
}
var noticeItem = RealtimeUpdate.makeNoticeItem(data);
$("#notices_primary .notices").prepend(noticeItem);
$("#notices_primary .notice:first").css({display:"none"});
$("#notices_primary .notice:first").fadeIn(1000);
RealtimeUpdate.updateWindowCounter();
},
if ($('#notices_primary .notice').length > RealtimeUpdate._maxnotices) {
$("#notices_primary .notice:last .form_disfavor").unbind('submit');
$("#notices_primary .notice:last .form_favor").unbind('submit');
$("#notices_primary .notice:last .notice_reply").unbind('click');
$("#notices_primary .notice:last").remove();
}
insertNoticeItem: function(data) {
// Don't add it if it already exists
if ($("#notice-"+data.id).length > 0) {
return;
}
SN.U.NoticeReply();
SN.U.NoticeFavor();
var noticeItem = RealtimeUpdate.makeNoticeItem(data);
$("#notices_primary .notices").prepend(noticeItem);
$("#notices_primary .notice:first").css({display:"none"});
$("#notices_primary .notice:first").fadeIn(1000);
SN.U.NoticeReply();
SN.U.NoticeFavor();
},
purgeLastNoticeItem: function() {
if ($('#notices_primary .notice').length > RealtimeUpdate._maxnotices) {
$("#notices_primary .notice:last .form_disfavor").unbind('submit');
$("#notices_primary .notice:last .form_favor").unbind('submit');
$("#notices_primary .notice:last .notice_reply").unbind('click');
$("#notices_primary .notice:last").remove();
}
},
updateWindowCounter: function() {
if (RealtimeUpdate._windowhasfocus === false) {
RealtimeUpdate._updatecounter += 1;
document.title = '('+RealtimeUpdate._updatecounter+') ' + DT;
document.title = '('+RealtimeUpdate._updatecounter+') ' + RealtimeUpdate._documenttitle;
}
},
@ -169,30 +189,83 @@ RealtimeUpdate = {
return dl;
},
addPopup: function(url, timeline, iconurl)
initActions: function(url, timeline, path)
{
var NP = $('#notices_primary');
NP.css({'position':'relative'});
NP.prepend('<button id="realtime_timeline" title="Pop up in a window">Pop up</button>');
var NP = $('#notices_primary');
NP.prepend('<ul id="realtime_actions"><li id="realtime_playpause"></li><li id="realtime_timeline"></li></ul>');
var RT = $('#realtime_timeline');
RT.css({
'margin':'0 0 11px 0',
'background':'transparent url('+ iconurl + ') no-repeat 0 30%',
'padding':'0 0 0 20px',
'display':'block',
'position':'absolute',
'top':'-20px',
'right':'0',
'border':'none',
'cursor':'pointer',
'color':$('a').css('color'),
'font-weight':'bold',
'font-size':'1em'
});
$('#showstream #notices_primary').css({'margin-top':'18px'});
RealtimeUpdate._pluginPath = path;
RT.bind('click', function() {
RealtimeUpdate.initPlayPause();
RealtimeUpdate.initAddPopup(url, timeline, RealtimeUpdate._pluginPath);
},
initPlayPause: function()
{
RealtimeUpdate.showPause();
},
showPause: function()
{
RT_PP = $('#realtime_playpause');
RT_PP.empty();
RT_PP.append('<button id="realtime_pause" class="pause" title="Pause">Pause</button>');
RT_P = $('#realtime_pause');
RT_P.bind('click', function() {
RealtimeUpdate._paused = true;
RealtimeUpdate.showPlay();
return false;
});
},
showPlay: function()
{
RT_PP = $('#realtime_playpause');
RT_PP.empty();
RT_PP.append('<span id="queued_counter"></span> <button id="realtime_play" class="play" title="Play">Play</button>');
RT_P = $('#realtime_play');
RT_P.bind('click', function() {
RealtimeUpdate._paused = false;
RealtimeUpdate.showPause();
RealtimeUpdate.showQueuedNotices();
return false;
});
},
showQueuedNotices: function()
{
$.each(RealtimeUpdate._queuedNotices, function(i, n) {
RealtimeUpdate.insertNoticeItem(n);
});
RealtimeUpdate._queuedNotices = [];
RealtimeUpdate.removeQueuedCounter();
},
updateQueuedCounter: function()
{
$('#realtime_playpause #queued_counter').html('('+RealtimeUpdate._queuedNotices.length+')');
},
removeQueuedCounter: function()
{
$('#realtime_playpause #queued_counter').empty();
},
initAddPopup: function(url, timeline, path)
{
var NP = $('#realtime_timeline');
NP.append('<button id="realtime_popup" title="Pop up in a window">Pop up</button>');
var PP = $('#realtime_popup');
PP.bind('click', function() {
window.open(url,
'',
'toolbar=no,resizable=yes,scrollbars=yes,status=yes,width=500,height=550');

View File

@ -1,3 +1,13 @@
cd `dirname $0`
cd ..
xgettext --from-code=UTF-8 --default-domain=statusnet --output=locale/statusnet.po --language=PHP --join-existing actions/*.php classes/*.php lib/*.php scripts/*.php
xgettext \
--from-code=UTF-8 \
--default-domain=statusnet \
--output=locale/statusnet.po \
--language=PHP \
--keyword="pgettext:1c,2" \
--keyword="npgettext:1c,2,3" \
actions/*.php \
classes/*.php \
lib/*.php \
scripts/*.php

View File

@ -107,6 +107,20 @@ clear:both;
.form_settings fieldset {
margin-bottom:29px;
}
.form_settings fieldset fieldset {
margin-bottom:41px;
padding:3% 1.795% 1.795% 3%;
border-radius:11px;
-moz-border-radius:11px;
-webkit-border-radius:11px;
border-width:1px;
border-style:solid;
}
.form_settings fieldset fieldset legend {
line-height:0;
}
.form_settings input.remove {
margin-left:11px;
}
@ -172,8 +186,7 @@ font-weight:bold;
#form_password_recover legend,
#form_password_change legend,
.form_entity_block legend,
#form_filter_bytag legend,
#settings_design_theme legend {
#form_filter_bytag legend {
display:none;
}
@ -939,7 +952,7 @@ clear:left;
float:left;
font-size:0.95em;
margin-left:59px;
width:50%;
max-width:74%;
}
#showstream .notice div.entry-content,
#shownotice .notice div.entry-content {
@ -961,7 +974,6 @@ position:relative;
font-size:0.95em;
width:90px;
float:right;
margin-right:11px;
}
.notice-options a {
@ -971,18 +983,12 @@ float:left;
.notice-options .notice_reply,
.notice-options .form_favor,
.notice-options .form_disfavor {
position:absolute;
top:0;
float:left;
margin-left:18px;
}
.notice-options .form_favor,
.notice-options .form_disfavor {
left:0;
}
.notice-options .notice_reply {
left:29px;
}
.notice-options .notice_delete {
right:0;
margin-left:0;
}
.notice-options input,
.notice-options a {
@ -1344,7 +1350,7 @@ float:left;
}
#settings_design_color .form_data {
width:400px;
margin-right:28px;
margin-right:1%;
}
#settings_design_color .form_data li {

View File

@ -28,10 +28,19 @@ input, textarea, select,
.entity_remote_subscribe {
border-color:#AAAAAA;
}
.form_settings fieldset fieldset {
background:rgba(240, 240, 240, 0.2);
box-shadow:3px 3px 7px rgba(194, 194, 194, 0.3);
-moz-box-shadow:3px 3px 7px rgba(194, 194, 194, 0.3);
-webkit-box-shadow:3px 3px 7px rgba(194, 194, 194, 0.3);
}
#filter_tags ul li,
.entity_send-a-message .form_notice,
.pagination .nav_prev a,
.pagination .nav_next a {
.pagination .nav_next a,
.form_settings fieldset fieldset {
border-color:#DDDDDD;
}
@ -52,8 +61,7 @@ input.submit,
.entity_remote_subscribe,
.entity_actions a,
.entity_actions input,
button.close {
background-color:#9BB43E;
button {
box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
-moz-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
-webkit-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);

View File

@ -28,10 +28,19 @@ input, textarea, select,
.entity_remote_subscribe {
border-color:#AAAAAA;
}
.form_settings fieldset fieldset {
background:rgba(240, 240, 240, 0.2);
box-shadow:3px 3px 7px rgba(194, 194, 194, 0.3);
-moz-box-shadow:3px 3px 7px rgba(194, 194, 194, 0.3);
-webkit-box-shadow:3px 3px 7px rgba(194, 194, 194, 0.3);
}
#filter_tags ul li,
.entity_send-a-message .form_notice,
.pagination .nav_prev a,
.pagination .nav_next a {
.pagination .nav_next a,
.form_settings fieldset fieldset {
border-color:#DDDDDD;
}
@ -52,7 +61,7 @@ input.submit,
.entity_remote_subscribe,
.entity_actions a,
.entity_actions input,
button.close {
button {
box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
-moz-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
-webkit-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);