- Facebook library. Used for the Facebook application.
- PEAR Services_oEmbed. Used for some multimedia integration.
- PEAR HTTP_Request is an oEmbed dependency.
-- PEAR Validat is an oEmbed dependency.e
-- PEAR Net_URL is an oEmbed dependency.2
+- PEAR Validate is an oEmbed dependency.
+- PEAR Net_URL2 is an oEmbed dependency.
A design goal of Laconica is that the basic Web functionality should
work on even the most restrictive commercial hosting services.
like 'image/gif', 'video/mpeg', 'audio/mpeg', etc. Make sure you
setup your server to properly reckognize the types you want to
support.
+uploads: false to disable uploading files with notices (true by default).
For quotas, be sure you've set the upload_max_filesize and post_max_size
in php.ini to be large enough to handle your upload. In httpd.conf
maxaliases: maximum number of aliases a group can have. Default 3. Set
to 0 or less to prevent aliases in a group.
+
+oohembed
+--------
+
+oEmbed endpoint for multimedia attachments (links in posts).
+
+endpoint: oohembed endpoint using http://oohembed.com/ software.
+
Troubleshooting
===============
function areYouSureForm()
{
$id = $this->profile->id;
+ $this->elementStart('form', array('id' => 'block-' . $id,
+ 'method' => 'post',
+ 'class' => 'form_settings form_entity_block',
+ 'action' => common_local_url('block')));
+ $this->elementStart('fieldset');
+ $this->hidden('token', common_session_token());
+ $this->element('legend', _('Block user'));
$this->element('p', null,
_('Are you sure you want to block this user? '.
'Afterwards, they will be unsubscribed from you, '.
'unable to subscribe to you in the future, and '.
'you will not be notified of any @-replies from them.'));
- $this->elementStart('form', array('id' => 'block-' . $id,
- 'method' => 'post',
- 'class' => 'block',
- 'action' => common_local_url('block')));
- $this->hidden('token', common_session_token());
$this->element('input', array('id' => 'blockto-' . $id,
'name' => 'blockto',
'type' => 'hidden',
$this->hidden($k, $v);
}
}
- $this->submit('no', _('No'));
- $this->submit('yes', _('Yes'));
+ $this->submit('form_action-no', _('No'), 'submit form_action-primary', 'no', _("Do not block this user from this group"));
+ $this->submit('form_action-yes', _('Yes'), 'submit form_action-secondary', 'yes', _('Block this user from this group'));
+ $this->elementEnd('fieldset');
$this->elementEnd('form');
}
exit(1);
}
-require_once(INSTALLDIR.'/lib/profilelist.php');
+require_once INSTALLDIR.'/lib/profilelist.php';
require_once INSTALLDIR.'/lib/publicgroupnav.php';
/**
$featured_nicks = common_config('nickname', 'featured');
-
if (count($featured_nicks) > 0) {
$quoted = array();
$cnt = $profile->find();
if ($cnt > 0) {
- $featured = new ProfileList($profile, null, $this);
+ $featured = new ProfileList($profile, $this);
$featured->show();
}
function areYouSureForm()
{
$id = $this->profile->id;
+ $this->elementStart('form', array('id' => 'block-' . $id,
+ 'method' => 'post',
+ 'class' => 'form_settings form_entity_block',
+ 'action' => common_local_url('groupblock')));
+ $this->elementStart('fieldset');
+ $this->hidden('token', common_session_token());
+ $this->element('legend', null, _('Block user'));
$this->element('p', null,
sprintf(_('Are you sure you want to block user "%s" from the group "%s"? '.
'They will be removed from the group, unable to post, and '.
'unable to subscribe to the group in the future.'),
$this->profile->getBestName(),
$this->group->getBestName()));
- $this->elementStart('form', array('id' => 'block-' . $id,
- 'method' => 'post',
- 'class' => 'block',
- 'action' => common_local_url('groupblock')));
- $this->hidden('token', common_session_token());
$this->hidden('blockto-' . $this->profile->id,
$this->profile->id,
'blockto');
$this->hidden($k, $v);
}
}
- $this->submit('no', _('No'));
- $this->submit('yes', _('Yes'));
+ $this->submit('form_action-no', _('No'), 'submit form_action-primary', 'no', _("Do not block this user from this group"));
+ $this->submit('form_action-yes', _('Yes'), 'submit form_action-secondary', 'yes', _('Block this user from this group'));
+ $this->elementEnd('fieldset');
$this->elementEnd('form');
}
$profile->query(sprintf($qry, $this->tag, $lim));
- $pl = new ProfileList($profile, null, $this);
+ $pl = new ProfileList($profile, $this);
$cnt = $pl->show();
$this->pagination($this->page > 1,
$user = $this->get_user($apidata['api_arg'], $apidata);
if (empty($user)) {
+ if ($apidata['content-type'] == 'xml') {
+ $this->show_single_xml_status($notice);
+ } elseif ($apidata['content-type'] == 'json') {
+ $this->show_single_json_status($notice);
+ }
$this->clientError('Not Found', 404, $apidata['content-type']);
return;
}
// Check for RESTfulness
if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) {
- // XXX: Twitter just prints the err msg, no XML / JSON.
$this->clientError(_('This method requires a POST or DELETE.'),
400, $apidata['content-type']);
return;
return;
}
- $user = $apidata['user']; // Always the auth user
-
+ $user = $apidata['user']; // Always the auth user
$notice_id = $apidata['api_arg'];
- $notice = Notice::staticGet($notice_id);
+ $notice = Notice::staticGet($notice_id);
if (empty($notice)) {
$this->clientError(_('No status found with that ID.'),
// XXX: Twitter lets you fave things repeatedly via api.
if ($user->hasFave($notice)) {
- $this->clientError(_('This notice is already a favorite!'),
+ $this->clientError(_('This status is already a favorite!'),
403, $apidata['content-type']);
return;
}
$fave = Fave::addNew($user, $notice);
if (empty($fave)) {
- $this->serverError(_('Could not create favorite.'));
+ $this->clientError(_('Could not create favorite.'));
return;
}
function destroy($args, $apidata)
{
parent::handle($args);
- $this->serverError(_('API method under construction.'), $code=501);
+
+ // Check for RESTfulness
+ if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) {
+ $this->clientError(_('This method requires a POST or DELETE.'),
+ 400, $apidata['content-type']);
+ return;
+ }
+
+ if (!in_array($apidata['content-type'], array('xml', 'json'))) {
+ $this->clientError(_('API method not found!'), $code = 404);
+ return;
+ }
+
+ $user = $apidata['user']; // Always the auth user
+ $notice_id = $apidata['api_arg'];
+ $notice = Notice::staticGet($notice_id);
+
+ if (empty($notice)) {
+ $this->clientError(_('No status found with that ID.'),
+ 404, $apidata['content-type']);
+ return;
+ }
+
+ $fave = new Fave();
+ $fave->user_id = $this->id;
+ $fave->notice_id = $notice->id;
+
+ if (!$fave->find(true)) {
+ $this->clientError(_('That status is not a favorite!'),
+ 403, $apidata['content-type']);
+ return;
+ }
+
+ $result = $fave->delete();
+
+ if (!$result) {
+ common_log_db_error($fave, 'DELETE', __FILE__);
+ $this->clientError(_('Could not delete favorite.'), 404);
+ return;
+ }
+
+ $user->blowFavesCache();
+
+ if ($apidata['content-type'] == 'xml') {
+ $this->show_single_xml_status($notice);
+ } elseif ($apidata['content-type'] == 'json') {
+ $this->show_single_json_status($notice);
+ }
+
}
// XXX: these two funcs swiped from faves.
&& ('text/html' === substr($redir_data['type'], 0, 9))
&& ($oembed_data = File_oembed::_getOembed($given_url))
&& isset($oembed_data['json'])) {
-
File_oembed::saveNew($oembed_data['json'], $file_id);
}
return $x;
if ($redir_url === $given_url) {
$x = File::saveNew($redir_data, $given_url);
$file_id = $x->id;
-
} else {
$x = File::processNew($redir_url, $notice_id);
$file_id = $x->id;
function _getOembed($url, $maxwidth = 500, $maxheight = 400, $format = 'json') {
- $cmd = 'http://oohembed.com/oohembed/?url=' . urlencode($url);
+ $cmd = common_config('oohembed', 'endpoint') . '?url=' . urlencode($url);
if (is_int($maxwidth)) $cmd .= "&maxwidth=$maxwidth";
if (is_int($maxheight)) $cmd .= "&maxheight=$maxheight";
if (is_string($format)) $cmd .= "&format=$format";
define('NOTICE_CACHE_WINDOW', 61);
+define('NOTICE_LOCAL_PUBLIC', 1);
+define('NOTICE_REMOTE_OMB', 0);
+define('NOTICE_LOCAL_NONPUBLIC', -1);
+define('NOTICE_GATEWAY', -2);
+
class Notice extends Memcached_DataObject
{
###START_AUTOCODE
$notice->addToInboxes();
$notice->saveGroups();
$notice->saveUrls();
+ $orig2 = clone($notice);
+ $notice->rendered = common_render_content($final, $notice);
+ if (!$notice->update($orig2)) {
+ common_log_db_error($notice, 'UPDATE', __FILE__);
+ return _('Problem saving notice.');
+ }
$notice->query('COMMIT');
* follow redirects and save all available file information
* (mimetype, date, size, oembed, etc.)
*
- * @param class $notice Notice to pull URLs from
- *
* @return void
*/
function saveUrls() {
$inbox = new Notice_inbox();
$UT = common_config('db','type')=='pgsql'?'"user"':'user';
$qry = 'INSERT INTO notice_inbox (user_id, notice_id, created, source) ' .
- "SELECT $UT.id, " . $this->id . ", '" . $this->created . "', 2 " .
+ "SELECT $UT.id, " . $this->id . ", '" . $this->created . "', " . NOTICE_INBOX_SOURCE_GROUP . " " .
"FROM $UT JOIN group_member ON $UT.id = group_member.profile_id " .
'WHERE group_member.group_id = ' . $group->id . ' ' .
'AND NOT EXISTS (SELECT user_id, notice_id ' .
define('INBOX_CACHE_WINDOW', 101);
+define('NOTICE_INBOX_SOURCE_SUB', 1);
+define('NOTICE_INBOX_SOURCE_GROUP', 2);
+define('NOTICE_INBOX_SOURCE_GATEWAY', -1);
+
class Notice_inbox extends Memcached_DataObject
{
###START_AUTOCODE
// $config['attachments']['file_quota'] = 5000000;
// $config['attachments']['user_quota'] = 50000000;
// $config['attachments']['monthly_quota'] = 15000000;
+// $config['attachments']['uploads'] = true;
+// $config['oohembed']['endpoint'] = 'http://oohembed.com/oohembed/';
};
$("#form_notice").ajaxForm(PostNotice);
$("#form_notice").each(addAjaxHidden);
- NoticeHover();
NoticeReply();
NoticeAttachments();
});
-
-function NoticeHover() {
- function mouseHandler(e) {
- $(e.target).closest('li.hentry')[(e.type === 'mouseover') ? 'addClass' : 'removeClass']('hover');
- };
- $('#content .notices').mouseover(mouseHandler);
- $('#content .notices').mouseout(mouseHandler);
-}
-
-
function NoticeReply() {
if ($('#notice_data-text').length > 0) {
$('#content .notice').each(function() {
$(this).closest(".entry-title").removeClass('ov');
}
);
-}
+}
\ No newline at end of file
'file_quota' => 5000000,
'user_quota' => 50000000,
'monthly_quota' => 15000000,
+ 'uploads' => true,
),
'group' =>
array('maxaliases' => 3),
+ 'oohembed' => array('endpoint' => 'http://oohembed.com/oohembed/')
);
$config['db'] = &PEAR::getStaticProperty('DB_DataObject','options');
$this->user = common_current_user();
}
- $this->enctype = 'multipart/form-data';
+ if (common_config('attachments', 'uploads')) {
+ $this->enctype = 'multipart/form-data';
+ }
}
/**
$this->out->element('dd', array('id' => 'notice_text-count'),
'140');
$this->out->elementEnd('dl');
- $this->out->element('label', array('for' => 'notice_data-attach'),_('Attach'));
- $this->out->element('input', array('id' => 'notice_data-attach',
- 'type' => 'file',
- 'name' => 'attach',
- 'title' => _('Attach a file')));
- $this->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota'));
+ if (common_config('attachments', 'uploads')) {
+ $this->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota'));
+ $this->out->element('label', array('for' => 'notice_data-attach'),_('Attach'));
+ $this->out->element('input', array('id' => 'notice_data-attach',
+ 'type' => 'file',
+ 'name' => 'attach',
+ 'title' => _('Attach a file')));
+ }
if ($this->action) {
$this->out->hidden('notice_return-to', $this->action, 'returnto');
}
$m->connect('api/favorites/:method/:argument',
array('action' => 'api',
- 'apiaction' => 'favorites'));
+ 'apiaction' => 'favorites',
+ array('method' => '(create|destroy)')));
$m->connect('api/favorites/:argument',
array('action' => 'api',
$this->init_twitter_atom();
break;
default:
- $this->client_error(_('Not a supported data format.'));
+ $this->clientError(_('Not a supported data format.'));
break;
}
$this->end_twitter_rss();
break;
default:
- $this->client_error(_('Not a supported data format.'));
+ $this->clientError(_('Not a supported data format.'));
break;
}
return;
}
- function client_error($msg, $code = 400, $content_type = 'json')
+ function clientError($msg, $code = 400, $content_type = 'json')
{
static $status = array(400 => 'Bad Request',
$this->show_json_objects($profile_array);
break;
default:
- $this->client_error(_('Not a supported data format.'));
+ $this->clientError(_('Not a supported data format.'));
return;
}
return;
#form_invite legend,
#form_notice_delete legend,
#form_password_recover legend,
-#form_password_change legend {
+#form_password_change legend,
+.form_entity_block legend {
display:none;
}
.entity_send-a-message a,
.entity_edit a,
.form_user_nudge input.submit,
-.entity_nudge p {
+.entity_nudge p,
+.form_make_admin input.submit {
border:0;
padding-left:20px;
}
.entity_send-a-message a,
.form_user_nudge input.submit,
.entity_nudge p,
-.form_settings input.form_action-primary {
+.form_settings input.form_action-primary,
+.form_make_admin input.submit {
color:#002E6E;
}
.form_user_unblock input.submit,
.form_group_block input.submit,
.form_group_unblock input.submit,
-.entity_nudge p {
+.entity_nudge p,
+.form_make_admin input.submit {
background-position: 0 40%;
background-repeat: no-repeat;
background-color:transparent;
.form_group_unblock input.submit {
background-image:url(../../base/images/icons/twotone/green/shield.gif);
}
+.form_make_admin input.submit {
+background-image:url(../../base/images/icons/twotone/green/admin.gif);
+}
/* NOTICES */
.notice .attachment {
}
.notices div.entry-content,
-.notices div.notice-options,
-.notices li.hover .notices div.entry-content,
-.notices li.hover .notices div.notice-options {
+.notices div.notice-options {
opacity:0.4;
}
-.notices li.hover div.entry-content,
-.notices li.hover div.notice-options {
+.notices li:hover div.entry-content,
+.notices li:hover div.notice-options {
opacity:1;
}
div.entry-content {
div.notice-options input {
font-family:sans-serif;
}
-.notices li.hover {
+.notices li:hover {
background-color:#FCFCFC;
}
+#conversation .notices li:hover {
+background-color:transparent;
+}
.notices .notices {
background-color:rgba(200, 200, 200, 0.050);
.entity_send-a-message a,
.form_user_nudge input.submit,
.entity_nudge p,
-.form_settings input.form_action-primary {
+.form_settings input.form_action-primary,
+.form_make_admin input.submit {
color:#002E6E;
}
.form_user_unblock input.submit,
.form_group_block input.submit,
.form_group_unblock input.submit,
-.entity_nudge p {
+.entity_nudge p,
+.form_make_admin input.submit {
background-position: 0 40%;
background-repeat: no-repeat;
background-color:transparent;
.form_group_unblock input.submit {
background-image:url(../../base/images/icons/twotone/green/shield.gif);
}
+.form_make_admin input.submit {
+background-image:url(../../base/images/icons/twotone/green/admin.gif);
+}
/* NOTICES */
.notice .attachment {
}
.notices div.entry-content,
-.notices div.notice-options,
-.notices li.hover .notices div.entry-content,
-.notices li.hover .notices div.notice-options {
+.notices div.notice-options {
opacity:0.4;
}
-.notices li.hover div.entry-content,
-.notices li.hover div.notice-options {
+.notices li:hover div.entry-content,
+.notices li:hover div.notice-options {
opacity:1;
}
div.entry-content {
div.notice-options input {
font-family:sans-serif;
}
-.notices li.hover {
+.notices li:hover {
background-color:#FCFCFC;
}
+#conversation .notices li:hover {
+background-color:transparent;
+}
.notices .notices {
background-color:rgba(200, 200, 200, 0.050);