This commit is contained in:
Habeas Codice 2015-02-16 15:13:31 -08:00
commit d9d029470f
41 changed files with 910 additions and 159 deletions

View File

@ -82,9 +82,8 @@ $DIRECTORY_FALLBACK_SERVERS = array(
'https://zothub.com',
'https://zotid.net',
'https://red.zottel.red',
'https://red.pixelbits.de',
'https://redmatrix.info',
'https://my.federated.social',
'https://whogotzot.com',
'https://redmatrix.nl'
);

View File

@ -50,6 +50,7 @@ Charles
Tony Baldwin
Hauke Zuehl
Keith Fernie
Anne Walk
toclimb
Daniel Frank
Matthew Exon

View File

@ -1,36 +1,37 @@
[h2]Database Tables[/h2]
[table]
[tr][th]Table[/th][th]Description[/th][/tr]
[tr][td][zrl=[baseurl]/help/db_abook]abook[/zrl][/td][td]contact table[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_abook]abook[/zrl][/td][td]connections of local channels[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_account]account[/zrl][/td][td]service provider account[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_addon]addon[/zrl][/td][td]registered plugins[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_app]app[/zrl][/td][td]peronal app data[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_app]app[/zrl][/td][td]personal app data[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_attach]attach[/zrl][/td][td]file attachments[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_auth_codes]auth_codes[/zrl][/td][td]OAuth usage[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_cache]cache[/zrl][/td][td]OEmbed cache[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_channel]channel[/zrl][/td][td][/td][/tr]
[tr][td][zrl=[baseurl]/help/db_channel]channel[/zrl][/td][td]local channels[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_chat]chat[/zrl][/td][td]chat room content[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_chatpresence]chatpresence[/zrl][/td][td]channel presence information for chat[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_chatroom]chatroom[/zrl][/td][td] data for the actual chat room[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_chatroom]chatroom[/zrl][/td][td]data for the actual chat room[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_clients]clients[/zrl][/td][td]OAuth usage[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_config]config[/zrl][/td][td]main configuration storage[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_conv]conv[/zrl][/td][td]Diaspora private messages[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_conv]conv[/zrl][/td][td]Diaspora private messages meta conversation structure[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_event]event[/zrl][/td][td]Events[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_fcontact]fcontact[/zrl][/td][td]friend suggestion stuff[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_ffinder]ffinder[/zrl][/td][td]friend suggestion stuff[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_fcontact]fcontact[/zrl][/td][td]friend suggestion stuff (obsolete)[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_ffinder]ffinder[/zrl][/td][td]friend suggestion stuff (obsolete)[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_fserver]fserver[/zrl][/td][td]obsolete[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_fsuggest]fsuggest[/zrl][/td][td]friend suggestion stuff[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_group_member]group_member[/zrl][/td][td]privacy groups[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_groups]groups[/zrl][/td][td]privacy groups[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_fsuggest]fsuggest[/zrl][/td][td]friend suggestion stuff (unused)[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_group_member]group_member[/zrl][/td][td]privacy groups (collections), group info[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_groups]groups[/zrl][/td][td]privacy groups (collections), member info[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_hook]hook[/zrl][/td][td]plugin hook registry[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_hubloc]hubloc[/zrl][/td][td]Red location storage, ties a location to an xchan[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_issue]issue[/zrl][/td][td][/td][/tr]
[tr][td][zrl=[baseurl]/help/db_item]item[/zrl][/td][td]posts[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_hubloc]hubloc[/zrl][/td][td]Red location storage, ties a hub location to an xchan[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_issue]issue[/zrl][/td][td]future bug/issue database[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_item]item[/zrl][/td][td]all posts and webpages[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_item_id]item_id[/zrl][/td][td]other identifiers on other services for posts[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_likes]likes[/zrl][/td][td]likes of 'things'[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_mail]mail[/zrl][/td][td]private messages[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_manage]manage[/zrl][/td][td]may be unused in Red, table of accounts that can "su" each other[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_menu]menu[/zrl][/td][td]channel menu data[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_menu_item]menu_item[/zrl][/td][td]items uses by channel menus[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_menu]menu[/zrl][/td][td]webpage menu data[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_menu_item]menu_item[/zrl][/td][td]entries for webpage menus[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_notify]notify[/zrl][/td][td]notifications[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_obj]obj[/zrl][/td][td]object data for things (x has y)[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_outq]outq[/zrl][/td][td]Red output queue[/td][/tr]
@ -49,7 +50,7 @@
[tr][td][zrl=[baseurl]/help/db_site]site[/zrl][/td][td]site table to find directory peers[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_source]source[/zrl][/td][td]channel sources data[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_spam]spam[/zrl][/td][td]unfinished[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_sys_perms]sys_perms[/zrl][/td][td]extensible permissions for the sys channel[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_sys_perms]sys_perms[/zrl][/td][td]extensible permissions for OAuth[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_term]term[/zrl][/td][td]item taxonomy (categories, tags, etc.) table[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_tokens]tokens[/zrl][/td][td]OAuth usage[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_updates]updates[/zrl][/td][td]directory sync updates[/td][/tr]
@ -58,8 +59,8 @@
[tr][td][zrl=[baseurl]/help/db_xchan]xchan[/zrl][/td][td]list of known channels in the universe[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_xchat]xchat[/zrl][/td][td]bookmarked chat rooms[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_xconfig]xconfig[/zrl][/td][td]as pconfig but for channels with no local account[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_xign]xign[/zrl][/td][td][/td][/tr]
[tr][td][zrl=[baseurl]/help/db_xlink]xlink[/zrl][/td][td]"friends of friends" linkages derived from poco[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_xign]xign[/zrl][/td][td]channels ignored by friend suggestions[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_xlink]xlink[/zrl][/td][td]"friends of friends" linkages derived from poco, also ratings storage[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_xprof]xprof[/zrl][/td][td]if this hub is a directory server, contains basic public profile info of everybody in the network[/td][/tr]
[tr][td][zrl=[baseurl]/help/db_xtag]xtag[/zrl][/td][td]if this hub is a directory server, contains tags or interests of everybody in the network[/td][/tr]
[/table]

View File

@ -8,16 +8,11 @@
[*][url=https://github.com/tonybaldwin/redmatrixthemes/]nubasic[/url]
[b]Third-Party Addons[/b]
[*][url=http://gitweb.whogotzot.com/red-addons-extra/tree]Additional RedMatrix addons[/url]
[*][url=https://abcentric.net/git/abcjsplugin.git]ABCjs integration - display scores in posts (WIP)[/url]
[*][url=http://gitweb.whogotzot.com/extra_dir_fns/tree]Extra directory functions[/url]
[b]Related Projects[/b]
[*][url=https://addons.mozilla.org/en-US/firefox/addon/redshare/]Redshare for Firefox[/url]
[*][url=https://github.com/cvogeley/red-for-android]Red for Android[/url]
[*][url=https://github.com/zzottel/feed2red]feed2red.pl (posts Atom/RSS feeds to channel)[/url]
[*][url=http://gitweb.whogotzot.com/red-stable/tree]Red Stable - up-to-date-but-not-bleeding-edge RedMatrix distribution[/url]
[b]Utilities[/b]
[*][url=http://gitweb.whogotzot.com/debian-install-script]Debian Install Script[/url]
#include doc/macros/main_footer.bb;

View File

@ -0,0 +1,8 @@
var NAVTREEINDEX10 =
{
"zot_8php.html#aeea071f17e306fe3d0c488551906bfab":[6,0,0,84,27],
"zotfeed_8php.html":[6,0,1,152],
"zotfeed_8php.html#a24dfc23d366e7f840cf2847d0c1c8eac":[6,0,1,152,0],
"zping_8php.html":[6,0,1,153],
"zping_8php.html#a4d3a6b0b8b04ed6469015823e615ee75":[6,0,1,153,0]
};

View File

@ -625,6 +625,7 @@ function bbcode($Text,$preserve_nl = false, $tryoembed = true) {
$Text = preg_replace("/\[table border=1\](.*?)\[\/table\]/sm", '<table border="1" >$1</table>' ,$Text);
$Text = preg_replace("/\[table border=0\](.*?)\[\/table\]/sm", '<table border="0" >$1</table>' ,$Text);
}
$Text = str_replace('</tr><br /><tr>',"</tr>\n<tr>",$Text);
$Text = str_replace('[hr]','<hr />', $Text);
// This is actually executed in prepare_body()

View File

@ -247,7 +247,7 @@ function sync_directories($dirmode) {
logger('rating updated');
}
else {
$z = q("insert into xlink ( xlink_xchan, xlink_link, xlink_rating, xlink_rating_text, xlink_sig, xlink_updated, xlink_static ) values( '%s', '%s', %d, '%s', '%s', 1 ) ",
$z = q("insert into xlink ( xlink_xchan, xlink_link, xlink_rating, xlink_rating_text, xlink_sig, xlink_updated, xlink_static ) values( '%s', '%s', %d, '%s', '%s', '%s', 1 ) ",
dbesc($rr['channel']),
dbesc($rr['target']),
intval($rr['rating']),

View File

@ -185,29 +185,6 @@ function poco_load($xchan = '',$url = null) {
$total ++;
$r = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 0 limit 1",
dbesc($xchan),
dbesc($hash)
);
if(! $r) {
q("insert into xlink ( xlink_xchan, xlink_link, xlink_rating, xlink_rating_text, xlink_updated, xlink_static ) values ( '%s', '%s', %d, '%s', '%s', 0 ) ",
dbesc($xchan),
dbesc($hash),
intval($rating),
dbesc($rating_text),
dbesc(datetime_convert())
);
}
else {
q("update xlink set xlink_updated = '%s', xlink_rating = %d, xlink_rating_text = '%s' where xlink_id = %d",
dbesc(datetime_convert()),
intval($rating),
dbesc($rating_text),
intval($r[0]['xlink_id'])
);
}
}
logger("poco_load: loaded $total entries",LOGGER_DEBUG);

View File

@ -962,4 +962,11 @@ function widget_rating($arr) {
return $o;
}
// used by site ratings pages to provide a return link
function widget_pubsites() {
if(get_app()->poi)
return;
return '<div class="widget"><ul class="nav nav-pills"><li><a href="pubsites">' . t('Public Hubs') . '</a></li></ul></div>';
}

View File

@ -2447,7 +2447,7 @@ function import_site($arr,$pubkey) {
}
$directory_url = htmlspecialchars($arr['directory_url'],ENT_COMPAT,'UTF-8',false);
$url = htmlspecialchars($arr['url'],ENT_COMPAT,'UTF-8',false);
$url = htmlspecialchars(strtolower($arr['url']),ENT_COMPAT,'UTF-8',false);
$sellpage = htmlspecialchars($arr['sellpage'],ENT_COMPAT,'UTF-8',false);
$site_location = htmlspecialchars($arr['location'],ENT_COMPAT,'UTF-8',false);
$site_realm = htmlspecialchars($arr['realm'],ENT_COMPAT,'UTF-8',false);

View File

@ -1,7 +0,0 @@
/*!
* Justified Gallery - v3.2.0
* http://miromannino.com/projects/justified-gallery/
* Copyright (c) 2014 Miro Mannino
* Licensed under the MIT license.
*/
@-webkit-keyframes justified-gallery-show-caption-animation{from{opacity:0}to{opacity:.7}}@-moz-keyframes justified-gallery-show-caption-animation{from{opacity:0}to{opacity:.7}}@-o-keyframes justified-gallery-show-caption-animation{from{opacity:0}to{opacity:.7}}@keyframes justified-gallery-show-caption-animation{from{opacity:0}to{opacity:.7}}@-webkit-keyframes justified-gallery-show-entry-animation{from{opacity:0}to{opacity:1}}@-moz-keyframes justified-gallery-show-entry-animation{from{opacity:0}to{opacity:1}}@-o-keyframes justified-gallery-show-entry-animation{from{opacity:0}to{opacity:1}}@keyframes justified-gallery-show-entry-animation{from{opacity:0}to{opacity:1}}.justified-gallery{width:100%;position:relative;overflow:hidden}.justified-gallery>a,.justified-gallery>div{position:absolute;display:inline-block;overflow:hidden;opacity:0;filter:alpha(opacity=0)}.justified-gallery>a>img,.justified-gallery>div>img{position:absolute;top:50%;left:50%;margin:0;padding:0;border:0}.justified-gallery>a>.caption,.justified-gallery>div>.caption{display:none;position:absolute;bottom:0;padding:5px;background-color:#000;left:0;right:0;margin:0;color:#fff;font-size:12px;font-weight:300;font-family:sans-serif}.justified-gallery>a>.caption.caption-visible,.justified-gallery>div>.caption.caption-visible{display:initial;opacity:.7;filter:"alpha(opacity=70)";-webkit-animation:justified-gallery-show-caption-animation 500ms 0 ease;-moz-animation:justified-gallery-show-caption-animation 500ms 0 ease;-ms-animation:justified-gallery-show-caption-animation 500ms 0 ease}.justified-gallery>.entry-visible{opacity:1;filter:alpha(opacity=100);-webkit-animation:justified-gallery-show-entry-animation 300ms 0 ease;-moz-animation:justified-gallery-show-entry-animation 300ms 0 ease;-ms-animation:justified-gallery-show-entry-animation 300ms 0 ease}.justified-gallery>.spinner{position:absolute;bottom:0;margin-left:-24px;padding:10px 0;left:50%;opacity:initial;filter:initial;overflow:initial}.justified-gallery>.spinner>span{display:inline-block;opacity:0;filter:alpha(opacity=0);width:8px;height:8px;margin:0 4px;background-color:#000;border-top-left-radius:6px;border-top-right-radius:6px;border-bottom-right-radius:6px;border-bottom-left-radius:6px}

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
/*
* Justified Gallery - v3.4.0
* http://miromannino.com/projects/justified-gallery/
* Copyright (c) 2014 Miro Mannino
/*!
* Justified Gallery - v3.5.4
* http://miromannino.github.io/Justified-Gallery/
* Copyright (c) 2015 Miro Mannino
* Licensed under the MIT license.
*/
(function($) {
@ -16,34 +16,37 @@
// Default options
var defaults = {
sizeRangeSuffixes : {
'lt100': '_t',
'lt240': '_m',
'lt320': '_n',
'lt500': '',
'lt640': '_z',
'lt1024': '_b'
'lt100': '', // e.g. Flickr uses '_t'
'lt240': '', // e.g. Flickr uses '_m'
'lt320': '', // e.g. Flickr uses '_n'
'lt500': '', // e.g. Flickr uses ''
'lt640': '', // e.g. Flickr uses '_z'
'lt1024': '', // e.g. Flickr uses '_b'
},
rowHeight : 120,
maxRowHeight : 0, //negative value = no limits, 0 = 1.5 * rowHeight
maxRowHeight : 0, // negative value = no limits, 0 = 1.5 * rowHeight
margins : 1,
border: -1, // negative value = same as margins, 0 = disabled
lastRow : 'nojustify', // or can be 'justify' or 'hide'
justifyThreshold: 0.75, /* if row width / available space > 0.75 it will be always justified
(i.e. lastRow setting is not considered) */
(i.e. lastRow setting is not considered) */
fixedHeight : false,
waitThumbnailsLoad : true,
captions : true,
cssAnimation: false,
imagesAnimationDuration : 500, //ignored with css animations
captionSettings : { //ignored with css animations
imagesAnimationDuration : 500, // ignored with css animations
captionSettings : { // ignored with css animations
animationDuration : 500,
visibleOpacity : 0.7,
nonVisibleOpacity : 0.0
},
rel : null, //rewrite the rel of each analyzed links
target : null, //rewrite the target of all links
rel : null, // rewrite the rel of each analyzed links
target : null, // rewrite the target of all links
extension : /\.[^.\\/]+$/,
refreshTime : 100,
randomize : false
randomize : false,
ignoreElement: null // a comma seperated list of div element selectors to be ignored e.g.: '.someClass, #someId'
};
function getSuffix(width, height, context) {
@ -136,12 +139,20 @@
}
}
function imgFromEntry($entry) {
var $img = $entry.find('> img');
if ($img.length === 0) $img = $entry.find('> a > img');
return $img;
}
function displayEntry($entry, x, y, imgWidth, imgHeight, rowHeight, context) {
var $image = $entry.find('img');
var $image = imgFromEntry($entry);
$image.css('width', imgWidth);
$image.css('height', imgHeight);
$image.css('margin-left', - imgWidth / 2);
$image.css('margin-top', - imgHeight / 2);
//if ($entry.get(0) === $image.parent().get(0)) { // this creates an error in link_around_img test
$image.css('margin-left', - imgWidth / 2);
$image.css('margin-top', - imgHeight / 2);
//}
$entry.width(imgWidth);
$entry.height(rowHeight);
$entry.css('top', y);
@ -165,9 +176,9 @@
}
if ($image.data('jg.loaded') === 'skipped') {
$image.one('load', function() {
onImageEvent(imageSrc, function() {
showImg($entry, loadNewImage, context);
$image.data('jg.loaded', 'loaded');
$image.data('jg.loaded', true);
});
} else {
showImg($entry, loadNewImage, context);
@ -216,8 +227,8 @@
var settings = context.settings;
var i, $entry, $image, imgAspectRatio, newImgW, newImgH, justify = true;
var minHeight = 0;
var availableWidth = context.galleryWidth - (
(context.buildingRow.entriesBuff.length - 1) * settings.margins);
var availableWidth = context.galleryWidth - 2 * context.border - (
(context.buildingRow.entriesBuff.length - 1) * settings.margins);
var rowHeight = availableWidth / context.buildingRow.aspectRatio;
var justificable = context.buildingRow.width / availableWidth > settings.justifyThreshold;
@ -237,11 +248,12 @@
if (isLastRow && !justificable && settings.lastRow === 'nojustify') justify = false;
for (i = 0; i < context.buildingRow.entriesBuff.length; i++) {
$image = context.buildingRow.entriesBuff[i].find('img');
$image = imgFromEntry(context.buildingRow.entriesBuff[i]);
imgAspectRatio = $image.data('jg.imgw') / $image.data('jg.imgh');
if (justify) {
newImgW = rowHeight * imgAspectRatio;
newImgW = (i === context.buildingRow.entriesBuff.length - 1) ? availableWidth
: rowHeight * imgAspectRatio;
newImgH = rowHeight;
/* With fixedHeight the newImgH must be greater than rowHeight.
@ -252,13 +264,15 @@
newImgW = settings.rowHeight * imgAspectRatio;
newImgH = settings.rowHeight;
}*/
} else {
newImgW = settings.rowHeight * imgAspectRatio;
newImgH = settings.rowHeight;
}
$image.data('jg.imgw', Math.ceil(newImgW));
$image.data('jg.imgh', Math.ceil(newImgH));
availableWidth -= Math.round(newImgW);
$image.data('jg.jimgw', Math.round(newImgW));
$image.data('jg.jimgh', Math.ceil(newImgH));
if (i === 0 || minHeight > newImgH) minHeight = newImgH;
}
@ -273,12 +287,12 @@
context.buildingRow.entriesBuff = [];
context.buildingRow.aspectRatio = 0;
context.buildingRow.width = 0;
context.offY = 0;
context.offY = context.border;
}
function flushRow(context, isLastRow) {
var settings = context.settings;
var $entry, $image, minHeight, buildingRowRes, offX = 0;
var $entry, $image, minHeight, buildingRowRes, offX = context.border;
//DEBUG// console.log('flush (isLastRow: ' + isLastRow + ')');
@ -298,14 +312,14 @@
for (var i = 0; i < context.buildingRow.entriesBuff.length; i++) {
$entry = context.buildingRow.entriesBuff[i];
$image = $entry.find('img');
displayEntry($entry, offX, context.offY, $image.data('jg.imgw'),
$image.data('jg.imgh'), minHeight, context);
offX += $image.data('jg.imgw') + settings.margins;
$image = imgFromEntry($entry);
displayEntry($entry, offX, context.offY, $image.data('jg.jimgw'),
$image.data('jg.jimgh'), minHeight, context);
offX += $image.data('jg.jimgw') + settings.margins;
}
//Gallery Height
context.$gallery.height(context.offY + minHeight +
context.$gallery.height(context.offY + minHeight + context.border +
(context.spinner.active ? context.spinner.$el.innerHeight() : 0)
);
@ -375,7 +389,7 @@
console.log('images status: ');
for (var i = 0; i < context.entries.length; i++) {
var $entry = $(context.entries[i]);
var $image = $entry.find('img');
var $image = imgFromEntry($entry);
console.log(i + ' (alt: ' + $image.attr('alt') + 'loaded: ' + $image.data('jg.loaded') + ')');
}*/
@ -385,12 +399,12 @@
for (var i = context.lastAnalyzedIndex + 1; i < context.entries.length; i++) {
var $entry = $(context.entries[i]);
var $image = $entry.find('img');
var $image = imgFromEntry($entry);
if ($image.data('jg.loaded') === true || $image.data('jg.loaded') === 'skipped') {
isLastRow = i >= context.entries.length - 1;
var availableWidth = context.galleryWidth - (
var availableWidth = context.galleryWidth - 2 * context.border - (
(context.buildingRow.entriesBuff.length - 1) * settings.margins);
var imgAspectRatio = $image.data('jg.imgw') / $image.data('jg.imgh');
if (availableWidth / (context.buildingRow.aspectRatio + imgAspectRatio) < settings.rowHeight) {
@ -475,6 +489,7 @@
}
checkOrConvertNumber(settings, 'margins');
checkOrConvertNumber(settings, 'border');
if (settings.lastRow !== 'nojustify' &&
settings.lastRow !== 'justify' &&
@ -516,6 +531,30 @@
}
function onImageEvent(imageSrc, onLoad, onError) {
if (!onLoad && !onError) {
return;
}
/* Check if the image is loaded or not using another image object.
We cannot use the 'complete' image property, because some browsers,
with a 404 set complete = true */
var memImage = new Image();
var $memImage = $(memImage);
if (onLoad) {
$memImage.one('load', function () {
$memImage.off('load error');
onLoad(memImage);
});
}
if (onError) {
$memImage.one('error', function() {
$memImage.off('load error');
onError(memImage);
});
}
memImage.src = imageSrc;
}
return this.each(function (index, gallery) {
var $gallery = $(gallery);
@ -529,10 +568,15 @@
// Spinner init
var $spinner = $('<div class="spinner"><span></span><span></span><span></span></div>');
var extendedSettings = $.extend({}, defaults, arg);
var border = extendedSettings.border >= 0 ? extendedSettings.border : extendedSettings.margins;
var ignoreElement = extendedSettings.ignoreElement;
//Context init
context = {
settings : $.extend({}, defaults, arg),
settings : extendedSettings,
imgAnalyzerTimeout : null,
entries : null,
buildingRow : {
@ -546,7 +590,8 @@
* must be greater than 1, else the analyzeImages will loop */
flushed : 0 //flushed rows without a yield
},
offY : 0,
border : border,
offY : border,
spinner : {
active : false,
phase : 0,
@ -556,7 +601,7 @@
intervalId : null
},
checkWidthIntervalId : null,
galleryWidth : $gallery.width(),
galleryWidth : $gallery.width(),
$gallery : $gallery
};
@ -571,12 +616,13 @@
// In this case we don't rewind, and analyze all the images
} else {
context.settings = $.extend({}, context.settings, arg);
context.border = context.settings.border >= 0 ? context.settings.border : context.settings.margins;
rewind(context);
}
checkSettings(context);
context.entries = $gallery.find('> a, > div:not(.spinner, #page-end)').toArray();
context.entries = $gallery.find('> a, > div:not(.spinner, ' + ignoreElement + ')').toArray();
if (context.entries.length === 0) return;
// Randomize
@ -588,9 +634,12 @@
}
var imagesToLoad = false;
var skippedImages = false;
$.each(context.entries, function (index, entry) {
var $entry = $(entry);
var $image = $entry.find('img');
var $image = imgFromEntry($entry);
$entry.addClass('jg-entry');
if ($image.data('jg.loaded') !== true && $image.data('jg.loaded') !== 'skipped') {
@ -612,6 +661,7 @@
$image.data('jg.imgw', width);
$image.data('jg.imgh', height);
$image.data('jg.loaded', 'skipped');
skippedImages = true;
startImgAnalyzer(context, false);
return true;
}
@ -627,32 +677,23 @@
startLoadingSpinnerAnimation(context.spinner);
}
/* Check if the image is loaded or not using another image object.
We cannot use the 'complete' image property, because some browsers,
with a 404 set complete = true */
var loadImg = new Image();
var $loadImg = $(loadImg);
$loadImg.one('load', function imgLoaded () {
onImageEvent(imageSrc, function imgLoaded (loadImg) {
//DEBUG// console.log('img load (alt: ' + $image.attr('alt') + ')');
$image.off('load error');
$image.data('jg.imgw', loadImg.width);
$image.data('jg.imgh', loadImg.height);
$image.data('jg.loaded', true);
startImgAnalyzer(context, false);
});
$loadImg.one('error', function imgLoadError () {
}, function imgLoadError () {
//DEBUG// console.log('img error (alt: ' + $image.attr('alt') + ')');
$image.off('load error');
$image.data('jg.loaded', 'error');
startImgAnalyzer(context, false);
});
loadImg.src = imageSrc;
}
});
if (!imagesToLoad) startImgAnalyzer(context, false);
if (!imagesToLoad && !skippedImages) startImgAnalyzer(context, false);
checkWidth(context);
});

View File

@ -1,7 +1,7 @@
/*!
* Justified Gallery - v3.2.0
* http://miromannino.com/projects/justified-gallery/
* Copyright (c) 2014 Miro Mannino
* Justified Gallery - v3.5.4
* http://miromannino.github.io/Justified-Gallery/
* Copyright (c) 2015 Miro Mannino
* Licensed under the MIT license.
*/
@-webkit-keyframes justified-gallery-show-caption-animation {
@ -83,7 +83,9 @@
/* IE8 or Earlier */
}
.justified-gallery > a > img,
.justified-gallery > div > img {
.justified-gallery > div > img,
.justified-gallery > a > a > img,
.justified-gallery > div > a > img {
position: absolute;
top: 50%;
left: 50%;
@ -103,6 +105,7 @@
margin: 0;
color: white;
font-size: 12px;
font-weight: 300;
font-family: sans-serif;
}
.justified-gallery > a > .caption.caption-visible,
@ -119,9 +122,9 @@
opacity: 1.0;
filter: alpha(opacity=100);
/* IE8 or Earlier */
-webkit-animation: justified-gallery-show-entry-animation 300ms 0 ease;
-moz-animation: justified-gallery-show-entry-animation 300ms 0 ease;
-ms-animation: justified-gallery-show-entry-animation 300ms 0 ease;
-webkit-animation: justified-gallery-show-entry-animation 500ms 0 ease;
-moz-animation: justified-gallery-show-entry-animation 500ms 0 ease;
-ms-animation: justified-gallery-show-entry-animation 500ms 0 ease;
}
.justified-gallery > .spinner {
position: absolute;

View File

@ -99,6 +99,7 @@ function acl_init(&$a){
intval(ABOOK_FLAG_BLOCKED|ABOOK_FLAG_PENDING|ABOOK_FLAG_ARCHIVED),
intval(XCHAN_FLAGS_DELETED)
);
}
else { // Visitors
$r = q("SELECT xchan_hash as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags
@ -148,12 +149,14 @@ function acl_init(&$a){
}
}
if(intval(get_config('system','taganyone')) || intval(get_pconfig(local_channel(),'system','taganyone'))) {
if((! $r) && $type == 'c') {
$r = q("SELECT substr(xchan_hash,1,18) as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags
if((count($r) < 100) && $type == 'c') {
$r2 = q("SELECT substr(xchan_hash,1,18) as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_their_perms, 0 as abook_flags
FROM xchan
WHERE not (xchan_flags & %d )>0 $sql_extra2 order by $order_extra2 xchan_name asc" ,
intval(XCHAN_FLAGS_DELETED)
);
if($r2)
$r = array_merge($r,$r2);
}
}
}

View File

@ -273,6 +273,10 @@ function events_content(&$a) {
$mode = 'add';
$item_id = intval(argv(2));
}
if(argc() > 2 && argv(1) === 'drop') {
$mode = 'drop';
$event_id = argv(2);
}
if(argv(1) === 'new') {
$mode = 'new';
$event_id = '';
@ -412,6 +416,8 @@ function events_content(&$a) {
$last_date = $d;
// FIXME
$edit = (($rr['item_flags'] & ITEM_WALL) ? array($a->get_baseurl().'/events/event/'.$rr['event_hash'],t('Edit event'),'','') : null);
$drop = array($a->get_baseurl().'/events/drop/'.$rr['event_hash'],t('Delete event'),'','');
$title = strip_tags(html_entity_decode(bbcode($rr['summary']),ENT_QUOTES,'UTF-8'));
if(! $title) {
list($title, $_trash) = explode("<br",bbcode($rr['desc']),2);
@ -425,6 +431,7 @@ function events_content(&$a) {
'hash' => $rr['event_hash'],
'start'=> $start,
'end' => $end,
'drop' => $drop,
'allDay' => false,
'title' => $title,
@ -479,6 +486,30 @@ function events_content(&$a) {
}
if($mode === 'drop' && $event_id) {
$r = q("SELECT * FROM `event` WHERE event_hash = '%s' AND `uid` = %d LIMIT 1",
dbesc($event_id),
intval(local_channel())
);
if($r) {
$r = q("delete from event where event_hash = '%s' and uid = %d limit 1",
dbesc($event_id),
intval(local_channel())
);
if($r) {
$r = q("update item set resource_type = '', resource_id = '' where resource_type = 'event' and resource_id = '%s' and uid = %d",
dbesc($event_id),
intval(local_channel())
);
info( t('Event removed') . EOL);
}
else {
notice( t('Failed to remove event' ) . EOL);
}
goaway(z_root() . '/events');
}
}
if($mode === 'edit' && $event_id) {
$r = q("SELECT * FROM `event` WHERE event_hash = '%s' AND `uid` = %d LIMIT 1",
dbesc($event_id),

View File

@ -164,9 +164,16 @@ function home_content(&$a, $update = 0, $load = false) {
}
require_once('include/identity.php');
$sys = get_sys_channel();
$uids = " and item.uid = " . intval($sys['channel_id']) . " ";
$a->data['firehose'] = intval($sys['channel_id']);
if(get_config('system','site_firehose')) {
require_once('include/security.php');
$uids = " and item.uid in ( " . stream_perms_api_uids(PERMS_PUBLIC) . " ) and item_private = 0 and (item_flags & " . intval(ITEM_WALL) . " ) > 0 ";
}
else {
$sys = get_sys_channel();
$uids = " and item.uid = " . intval($sys['channel_id']) . " ";
$a->data['firehose'] = intval($sys['channel_id']);
}
$page_mode = 'list';
@ -199,6 +206,7 @@ function home_content(&$a, $update = 0, $load = false) {
intval(ABOOK_FLAG_BLOCKED)
);
}
// Then fetch all the children of the parents that are on this page

View File

@ -644,7 +644,7 @@ function item_post(&$a) {
}
}
$item_unseen = ((local_channel() != $profile_uid) ? 1 : 0);
$item_unseen = 1;
if($post_type === 'wall' || $post_type === 'wall-comment')
$item_flags = $item_flags | ITEM_WALL;

View File

@ -977,10 +977,10 @@ function photos_content(&$a) {
if($r) {
foreach($r as $item) {
like_puller($a,$item,$alike,'like');
like_puller($a,$item,$dlike,'dislike');
}
// foreach($r as $item) {
// like_puller($a,$item,$alike,'like');
// like_puller($a,$item,$dlike,'dislike');
// }
$like_count = ((x($alike,$link_item['mid'])) ? $alike[$link_item['mid']] : '');
$like_list = ((x($alike,$link_item['mid'])) ? $alike[$link_item['mid'] . '-l'] : '');

View File

@ -467,7 +467,7 @@ function post_post(&$a) {
* tells us we need to unencapsulate the AES-256-CBC content using the site private key
*/
if(array_key_exists('iv',$data)) {
if($data && array_key_exists('iv',$data)) {
$encrypted_packet = true;
$data = crypto_unencapsulate($data,get_config('system','prvkey'));
logger('mod_zot: decrypt1: ' . $data, LOGGER_DATA);

View File

@ -22,10 +22,13 @@ function pubsites_content(&$a) {
if($ret['success']) {
$j = json_decode($ret['body'],true);
if($j) {
$o .= '<table border="1"><tr><td>' . t('Site URL') . '</td><td>' . t('Access Type') . '</td><td>' . t('Registration Policy') . '</td><td>' . t('Location') . '</td></tr>';
$rate_meta = ((local_channel()) ? '<td>' . t('Rate this hub') . '</td>' : '');
$o .= '<table border="1"><tr><td>' . t('Site URL') . '</td><td>' . t('Access Type') . '</td><td>' . t('Registration Policy') . '</td><td>' . t('Location') . '</td><td>' . t('View hub ratings') . '</td>' . $rate_meta . '</tr>';
if($j['sites']) {
foreach($j['sites'] as $jj) {
$o .= '<tr><td>' . '<a href="'. (($jj['sellpage']) ? $jj['sellpage'] : $jj['url'] . '/register' ) . '" >' . $jj['url'] . '</a>' . '</td><td>' . $jj['access'] . '</td><td>' . $jj['register'] . '</td><td>' . $jj['location'] . '</td></tr>';
$host = strtolower(substr($jj['url'],strpos($jj['url'],'://')+3));
$rate_links = ((local_channel()) ? '<td><a href="rate?f=&target=' . $host . '" class="btn-btn-default"><i class="icon-check"></i> ' . t('Rate') . '</a></td>' : '');
$o .= '<tr><td>' . '<a href="'. (($jj['sellpage']) ? $jj['sellpage'] : $jj['url'] . '/register' ) . '" >' . $jj['url'] . '</a>' . '</td><td>' . $jj['access'] . '</td><td>' . $jj['register'] . '</td><td>' . $jj['location'] . '</td><td><a href="ratings/' . $host . '" class="btn-btn-default"><i class="icon-eye-open"></i> ' . t('View ratings') . '</a></td>' . $rate_links . '</tr>';
}
}

View File

@ -21,6 +21,15 @@ function rate_init(&$a) {
if($r) {
$a->poi = $r[0];
}
else {
$r = q("select * from site where site_url like '%s' ",
dbesc('%' . $target)
);
if($r) {
$a->data['site'] = $r[0];
$a->data['site']['site_url'] = strtolower($r[0]['site_url']);
}
}
}
@ -119,12 +128,15 @@ function rate_content(&$a) {
dbesc($channel['channel_hash']),
dbesc($a->data['target'])
);
if($r)
if($r) {
$a->data['xlink'] = $r[0];
$rating_val = $r[0]['xlink_rating'];
$rating_text = $r[0]['xlink_rating_text'];
$rating_val = $r[0]['xlink_rating'];
$rating_text = $r[0]['xlink_rating_text'];
}
else {
$rating_val = 0;
$rating_text = '';
}
// if unset default to enabled
if($poco_rating === false)
@ -142,6 +154,8 @@ function rate_content(&$a) {
$o = replace_macros(get_markup_template('rating_form.tpl'),array(
'$header' => t('Rating'),
'$website' => t('Website:'),
'$site' => (($a->data['site']) ? '<a href="' . $a->data['site']['site_url'] . '" >' . $a->data['site']['site_url'] . '</a>' : ''),
'target' => $a->data['target'],
'$tgt_name' => (($a->poi && $a->poi['xchan_name']) ? $a->poi['xchan_name'] : sprintf( t('Remote Channel [%s] (not yet known on this site)'), substr($a->data['target'],0,16))),
'$lbl_rating' => t('Rating (this information is public)'),

View File

@ -35,7 +35,7 @@ function ratings_init(&$a) {
$results = false;
$x = z_fetch_url($url . '/ratingsearch/' . $hash);
$x = z_fetch_url($url . '/ratingsearch/' . urlencode($hash));
if($x['success'])
@ -48,8 +48,9 @@ function ratings_init(&$a) {
return;
}
$a->poi = $results['target'];
if(array_key_exists('xchan_hash',$results['target']))
$a->poi = $results['target'];
$friends = array();
$others = array();
@ -62,9 +63,9 @@ function ratings_init(&$a) {
}
}
$a->data = array_merge($friends,$others);
$a->data = array('target' => $results['target'], 'results' => array_merge($friends,$others));
if(! $a->data) {
if(! $a->data['results']) {
notice( t('No ratings') . EOL);
}
@ -90,11 +91,17 @@ function ratings_content(&$a) {
if(! $poco_rating)
return;
$site_target = ((array_key_exists('target',$a->data) && array_key_exists('site_url',$a->data['target'])) ?
'<a href="' . $a->data['target']['site_url'] . '" >' . $a->data['target']['site_url'] . '</a>' : '');
$o = replace_macros(get_markup_template('prep.tpl'),array(
'$header' => t('Ratings'),
'$rating_lbl' => t('Rating: ' ),
'$website' => t('Website: '),
'$site' => $site_target,
'$rating_text_lbl' => t('Description: '),
'$raters' => $a->data
'$raters' => $a->data['results']
));
return $o;

View File

@ -33,17 +33,28 @@ function ratingsearch_init(&$a) {
);
if($p)
$ret['target'] = $p[0];
$target = $p[0]['xchan_hash'];
else {
$ret['message'] = 'channel not found';
json_return_and_die($ret);
$p = q("select * from site where site_url like '%s' ",
dbesc('%' . $hash)
);
if($p) {
$target = strtolower($hash);
}
else {
$ret['message'] = 'Rating target not found';
json_return_and_die($ret);
}
}
if($p)
$ret['target'] = $p[0];
$ret['success'] = true;
$r = q("select * from xlink left join xchan on xlink_xchan = xchan_hash
where xlink_link = '%s' and xlink_rating != 0 and xlink_static = 1 order by xchan_name asc",
dbesc($p[0]['xchan_hash'])
dbesc($target)
);
if($r) {

109
util/zotsh/README.txt Normal file
View File

@ -0,0 +1,109 @@
ZotSH - v.0.0.2
Client for browsing RedDAVs.
Install
-------
ZotSH requires 'requests'(1).
Please refer to requests docs on how to install it (2)
Extract somewere and launch zotsh.py
Description
-----------
ZotSH is a command line WebDAV client for RedMatrix.
It knows how to magic-auth to remote hubs using Zot.
ZotSH uses 'easywebdav' library (0) with small modifications
to 'zotify' it. (See easywebdav/LICENSE)
Commands
--------
host <hostname>
Authenticate to 'hostname' and switch to it
cd <dirname|..>
changhe remote dir
ls [path] [-a] [-l] [-d]
list remote files in current dir if 'path' not defined
-a list all, show hidden dot-files
-l list verbose
-d list only dirs
exists <path>
Check existence of 'path'
mkdir <name>
Create directory 'name'
mkdirs <path>
Create parent directories to path, if they don't exists
rmdir <name>
Delete directory 'name'
delete <path>
Delete file 'path'
upload <local_path> [remote_path]
Upload local file 'local_paht' to 'remote_paht'
download <remote_path> [local_path]
Download remote file 'remote_path' and save it as 'local_path'
cat <remote_paht>
Print content of 'remote_path'
pwd
Print current path
lcd
lpwd
lls
Local file management
quit
help
Config
------
Create a .zotshrc file in your home or in same folder with zotsh.py:
[zotsh]
host = https://yourhost.com/
username = your_username
password = your_password
Optionally adds
verify_ssl = false
to skip verification of ssl certs
Changelog
----------
0.0.2 Fix "CommandNotFound" exception, new 'cat' command
0.0.1 First release
Links
-----
_0 : https://github.com/amnong/easywebdav
_1 : http://docs.python-requests.org/en/latest/
_2 : http://docs.python-requests.org/en/latest/user/install/

View File

@ -0,0 +1,5 @@
Copyright (c) 2012 year, Amnon Grossman
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@ -0,0 +1,5 @@
from .client import *
def connect(*args, **kwargs):
"""connect(host, port=0, auth=None, username=None, password=None, protocol='http', path="/")"""
return Client(*args, **kwargs)

Binary file not shown.

View File

@ -0,0 +1 @@
__version__ = "1.2.0"

Binary file not shown.

View File

@ -0,0 +1,202 @@
import requests
import platform
from numbers import Number
import xml.etree.cElementTree as xml
from collections import namedtuple
py_majversion, py_minversion, py_revversion = platform.python_version_tuple()
if py_majversion == '2':
from httplib import responses as HTTP_CODES
from urlparse import urlparse
else:
from http.client import responses as HTTP_CODES
from urllib.parse import urlparse
DOWNLOAD_CHUNK_SIZE_BYTES = 1 * 1024 * 1024
class WebdavException(Exception):
pass
class ConnectionFailed(WebdavException):
pass
def codestr(code):
return HTTP_CODES.get(code, 'UNKNOWN')
File = namedtuple('File', ['name', 'size', 'mtime', 'ctime', 'contenttype'])
def prop(elem, name, default=None):
child = elem.find('.//{DAV:}' + name)
return default if child is None else child.text
def elem2file(elem):
return File(
prop(elem, 'href'),
int(prop(elem, 'getcontentlength', 0)),
prop(elem, 'getlastmodified', ''),
prop(elem, 'creationdate', ''),
prop(elem, 'getcontenttype', ''),
)
class OperationFailed(WebdavException):
_OPERATIONS = dict(
HEAD = "get header",
GET = "download",
PUT = "upload",
DELETE = "delete",
MKCOL = "create directory",
PROPFIND = "list directory",
)
def __init__(self, method, path, expected_code, actual_code):
self.method = method
self.path = path
self.expected_code = expected_code
self.actual_code = actual_code
operation_name = self._OPERATIONS[method]
self.reason = 'Failed to {operation_name} "{path}"'.format(**locals())
expected_codes = (expected_code,) if isinstance(expected_code, Number) else expected_code
expected_codes_str = ", ".join('{0} {1}'.format(code, codestr(code)) for code in expected_codes)
actual_code_str = codestr(actual_code)
msg = '''\
{self.reason}.
Operation : {method} {path}
Expected code : {expected_codes_str}
Actual code : {actual_code} {actual_code_str}'''.format(**locals())
super(OperationFailed, self).__init__(msg)
class Client(object):
def __init__(self, host, port=0, auth=None, username=None, password=None,
protocol='http', verify_ssl=True, path=None, cert=None, session=None):
if not port:
port = 443 if protocol == 'https' else 80
self.baseurl = '{0}://{1}:{2}'.format(protocol, host, port)
if path:
self.baseurl = '{0}/{1}'.format(self.baseurl, path)
self.cwd = '/'
if session is None:
self.session = requests.session()
else:
self.session = session
self.session.verify = verify_ssl
self.session.stream = True
if cert:
self.session.cert = cert
if auth:
self.session.auth = auth
elif username and password:
self.session.auth = (username, password)
def _send(self, method, path, expected_code, **kwargs):
url = self._get_url(path).strip(".")
#~ print self.session
#~ print self.session.verify
#~ print self.session.params
#~ print self.session.cookies
response = self.session.request(method, url, allow_redirects=False, **kwargs)
#~ print response.request.method
#~ print response.request.url
if isinstance(expected_code, Number) and response.status_code != expected_code \
or not isinstance(expected_code, Number) and response.status_code not in expected_code:
raise OperationFailed(method, path, expected_code, response.status_code)
return response
def _get_url(self, path):
path = str(path).strip()
if path.startswith('/'):
return self.baseurl + path
return "".join((self.baseurl, self.cwd, path))
def cd(self, path):
path = path.strip()
if not path:
return
stripped_path = '/'.join(part for part in path.split('/') if part) + '/'
if stripped_path == '/':
self.cwd = stripped_path
elif path.startswith('/'):
self.cwd = '/' + stripped_path
elif stripped_path == "./":
return
elif stripped_path == "../":
self.cwd ='/'.join( self.cwd.split('/')[:-2] ) + '/'
else:
self.cwd += stripped_path
def mkdir(self, path, safe=False):
expected_codes = 201 if not safe else (201, 301, 405)
self._send('MKCOL', path, expected_codes)
def mkdirs(self, path):
dirs = [d for d in path.split('/') if d]
if not dirs:
return
if path.startswith('/'):
dirs[0] = '/' + dirs[0]
old_cwd = self.cwd
try:
for dir in dirs:
try:
self.mkdir(dir, safe=True)
except Exception as e:
if e.actual_code == 409:
raise
finally:
self.cd(dir)
finally:
self.cd(old_cwd)
def rmdir(self, path, safe=False):
path = str(path).rstrip('/') + '/'
expected_codes = 204 if not safe else (204, 404)
self._send('DELETE', path, expected_codes)
def delete(self, path):
self._send('DELETE', path, 204)
def upload(self, local_path_or_fileobj, remote_path):
if isinstance(local_path_or_fileobj, basestring):
with open(local_path_or_fileobj, 'rb') as f:
self._upload(f, remote_path)
else:
self._upload(local_path_or_fileobj, remote_path)
def _upload(self, fileobj, remote_path):
self._send('PUT', remote_path, (200, 201, 204), data=fileobj)
def download(self, remote_path, local_path_or_fileobj):
response = self._send('GET', remote_path, 200, stream=True)
if isinstance(local_path_or_fileobj, basestring):
with open(local_path_or_fileobj, 'wb') as f:
self._download(f, response)
else:
self._download(local_path_or_fileobj, response)
def _download(self, fileobj, response):
for chunk in response.iter_content(DOWNLOAD_CHUNK_SIZE_BYTES):
fileobj.write(chunk)
def ls(self, remote_path='.'):
headers = {'Depth': '1'}
response = self._send('PROPFIND', remote_path, (207, 301), headers=headers)
# Redirect
if response.status_code == 301:
url = urlparse(response.headers['location'])
return self.ls(url.path)
tree = xml.fromstring(response.content)
return [elem2file(elem) for elem in tree.findall('{DAV:}response')]
def exists(self, remote_path):
response = self._send('HEAD', remote_path, (200, 301, 404))
return True if response.status_code != 404 else False

Binary file not shown.

324
util/zotsh/zotsh.py Executable file
View File

@ -0,0 +1,324 @@
#!/usr/bin/env python2
import sys, os
import ConfigParser
import requests
from requests.auth import HTTPBasicAuth
import easywebdav
import easywebdav.__version__ as easywebdavversion
__version__= "0.0.2"
SERVER = None
USER = None
PASSWD = None
VERIFY_SSL=True
#####################################################
class CommandNotFound(Exception):
pass
class ZotSH(object):
commands = ['cd','ls','exists','mkdir','mkdirs','rmdir','delete','upload','download',
'host', 'pwd','cat',
'lcd','lpwd', 'lls',
'quit', 'help']
def __init__(self, host, session=None, davclient=None):
self.sessions = {}
self.host = host
self.session = session
self.davclient = davclient
@property
def host(self):
return self._host
@host.setter
def host(self, host):
self._host = host
self._hostname = host.replace("https:","").replace("/","")
@property
def hostname(self):
return self._hostname
@hostname.setter
def hostname(self, hostname):
self._host = "https://%s/" % (hostname)
self._hostname = hostname
@property
def session(self):
return self._session
@session.setter
def session(self, session):
self._session = session
self.davclient = easywebdav.connect( self.hostname, protocol='https', session=session, path="cloud", verify_ssl=VERIFY_SSL)
@property
def PS1(self):
if self.davclient is None:
return "[!]> "
return "%s:%s> " % (self.hostname, self.davclient.cwd)
def get_host_session(self, host=None):
#~ if host is None:
#~ host = self.host
#~ if not host.startswith("https"):
#~ host = "https://%s/" % (host)
#~ if host in self.sessions:
#~ session = self.sessions[host]
#~ else:
#~ session = requests.Session()
#~ self.sessions[host] = session
#~ if not host == SERVER
#~ session.params.update({'davguest':1})
#~ return session
if self.session is None:
session = requests.Session()
#session.params.update({'davguest':1})
else:
session = self.session
session.params.update({'davguest': (not host == SERVER) })
return session
def do(self, command, *args):
if not command in self.commands:
raise CommandNotFound("Unknow command '%s'" % command)
cmd = getattr(self, "cmd_%s"%command, None)
if cmd is None:
cmd = getattr(self.davclient, command)
return cmd(*args)
def cmd_exists(self, *args):
if (len(args)==0):
return
return self.davclient.exists(args[0])
def cmd_mkdir(self, *args):
if (len(args)==0):
return
return self.davclient.mkdir(args[0])
def cmd_mkdirs(self, *args):
if (len(args)==0):
return
return self.davclient.mkdirs(args[0])
def cmd_rmdir(self, *args):
if (len(args)==0):
return
return self.davclient.rmdir(args[0])
def cmd_delete(self, *args):
if (len(args)==0):
return
return self.davclient.delete(args[0])
def cmd_upload(self, *args):
if (len(args)==0):
return
args = list(args)
if (len(args)==1):
args.append(args[0])
return self.davclient.upload(args[0], args[1])
def cmd_download(self, *args):
if (len(args)==0):
return
args = list(args)
if (len(args)==1):
args.append(args[0])
return self.davclient.download(args[0], args[1])
def cmd_host(self, *args):
if (len(args)==0):
return
newhostname = args[0]
newhost = "https://%s/" % newhostname
if newhostname == "~" or newhost == SERVER:
# bach to home server
self.host = SERVER
self.session = self.get_host_session(SERVER)
return
session_remote = self.get_host_session(newhost)
session_home = self.get_host_session(SERVER)
# call /magic on SERVER
r = session_home.get(
SERVER + "magic",
params={'dest': newhost},
allow_redirects=False,
verify=VERIFY_SSL )
if not 'location' in r.headers:
raise Exception("Cannot start magic auth to '%s'" % newhostname)
auth_url = r.headers['location']
# call auth_url with "test" param
r = session_remote.get(
auth_url,
params={'test': 1 },
verify=VERIFY_SSL )
if r.json()['success']:
self.hostname = newhostname
self.session = session_remote
else:
raise Exception("Cannot magic auth to '%s'" % newhostname)
def cmd_pwd(self, *args):
return "%s%s" % ( self.davclient.baseurl, self.davclient.cwd )
def cmd_ls(self, *args):
extra_args = ["-a", "-l", "-d"]
show_hidden = "-a" in args
show_list = "-l" in args
show_only_dir = "-d" in args
args = [ a for a in args if not a in extra_args ]
r = self.davclient.ls(*args)
l = max([ len(str(f.size)) for f in r ] + [7,])
def _fmt(type, size, name):
if show_list:
return "%s %*d %s" % (type, l, f.size , name)
else:
return name
if show_hidden :
print _fmt('d', 0, "./")
if self.davclient.cwd!="/":
print _fmt('d', 0, "../")
for f in r:
name = f.name.replace("/cloud"+self.davclient.cwd,"")
type = "-"
if name.endswith("/"):
type = "d"
if name!="":
if show_hidden or not name.startswith("."):
if not show_only_dir or type=="d":
print _fmt(type, f.size , name)
def cmd_lpwd(self, *args):
return os.getcwd()
def cmd_lcd(self, *args):
if (len(args)==0):
return
os.chdir(args[0])
def cmd_lls(self, *args):
for f in os.listdir(os.getcwd()):
if os.path.isdir(f):
f=f+"/"
print f
def cmd_help(self, *args):
print "ZotSH",__version__
print
print "Commands:"
for c in self.commands:
print "\t",c
print
print "easywebdav", easywebdavversion.__version__, "(mod)"
print "requests", requests.__version__
def cmd_cat(self,*args):
if (len(args)==0):
return
rfile = args[0]
resp = self.davclient._send('GET', rfile, (200,))
print resp.text
def load_conf():
global SERVER,USER,PASSWD,VERIFY_SSL
homedir = os.getenv("HOME")
if homedir is None:
homedir = os.path.join(os.getenv("HOMEDRIVE"), os.getenv("HOMEPATH"))
optsfile = ".zotshrc"
if not os.path.isfile(optsfile):
optsfile = os.path.join(homedir, ".zotshrc")
if not os.path.isfile(optsfile):
print "Please create a configuration file called '.zotshrc':"
print "[zotsh]"
print "host = https://yourhost.com/"
print "username = your_username"
print "password = your_password"
sys.exit(-1)
config = ConfigParser.ConfigParser()
config.read(optsfile)
SERVER = config.get('zotsh', 'host')
USER = config.get('zotsh', 'username')
PASSWD = config.get('zotsh', 'password')
if config.has_option('zotsh', 'verify_ssl'):
VERIFY_SSL = config.getboolean('zotsh', 'verify_ssl')
def zotsh():
zotsh = ZotSH( SERVER)
session_home = zotsh.get_host_session()
#~ #login on home server
print "loggin in..."
r = session_home.get(
SERVER + "api/account/verify_credentials",
auth=HTTPBasicAuth(USER, PASSWD),
verify=VERIFY_SSL )
print "Hi", r.json()['name']
zotsh.session = session_home
# command loop
input = raw_input(zotsh.PS1)
while (input != "quit"):
input = input.strip()
if len(input)>0:
toks = [ x.strip() for x in input.split(" ") ]
command = toks[0]
args = toks[1:]
try:
ret = zotsh.do(command, *args)
except easywebdav.client.OperationFailed, e:
print e
except CommandNotFound, e:
print e
else:
if ret is not None:
print ret
input = raw_input(zotsh.PS1)
if __name__=="__main__":
load_conf()
zotsh()
sys.exit()

View File

@ -1 +1 @@
2015-02-13.943
2015-02-16.946

View File

@ -713,6 +713,8 @@ function updateConvItems(mode,data) {
justifiedGalleryActive = true;
$('#photo-album-contents').justifiedGallery({
margins: 3,
border: 0,
ignoreElement: '#page-end',
sizeRangeSuffixes: {
'lt100': '-2',
'lt240': '-2',

View File

@ -1,4 +1,5 @@
[region=aside]
[widget=pubsites][/widget]
[widget=vcard][/widget]
[widget=rating][/widget]
[widget=suggestions][/widget]

View File

@ -9,11 +9,11 @@ head_add_css('library/jRange/jquery.range.css');
head_add_css('view/css/conversation.css');
head_add_css('view/css/widgets.css');
head_add_css('view/css/colorbox.css');
head_add_css('library/justifiedGallery/dist/css/justifiedGallery.css');
head_add_css('library/justifiedGallery/justifiedGallery.css');
head_add_css('library/bootstrap-tagsinput/bootstrap-tagsinput.css');
head_add_js('jquery.js');
head_add_js('jquery-migrate-1.1.1.js');
head_add_js('library/justifiedGallery/dist/js/jquery.justifiedGallery.js');
head_add_js('library/justifiedGallery/jquery.justifiedGallery.js');
//head_add_js('jquery-compat.js');
head_add_js('spin.js');

View File

@ -992,7 +992,7 @@ nav .acpopup {
margin-bottom: 10px;
}
.edit-event-link, .plink-event-link {
.edit-event-link, .plink-event-link, .drop-event-link {
float: left;
margin-top: 4px;
margin-right: 4px;

View File

@ -8,6 +8,7 @@
<div class="event-buttons">
{{if $event.item.plink}}<a href="{{$event.plink.0}}" title="{{$event.plink.1}}" class="plink-event-link"><i class="icon-external-link btn btn-default" ></i></a>{{/if}}
{{if $event.edit}}<a href="{{$event.edit.0}}" title="{{$event.edit.1}}" class="edit-event-link"><i class="icon-pencil btn btn-default"></i></a>{{/if}}
{{if $event.drop}}<a href="{{$event.drop.0}}" title="{{$event.drop.1}}" class="drop-event-link"><i class="icon-trash btn btn-default"></i></a>{{/if}}
</div>
</div>
<div class="clear"></div>

View File

@ -1,5 +1,10 @@
<h1>{{$header}}</h1>
{{if $site}}
<h3>{{$website}} {{$site}}</h3>
{{/if}}
{{if $raters}}
{{foreach $raters as $r}}

View File

@ -1,6 +1,6 @@
<h3>{{$header}}</h3>
<div class="rating-target-name">{{$tgt_name}}</div>
<div class="rating-target-name">{{if $site}}{{$website}} {{$site}}{{else}}{{$tgt_name}}{{/if}}</div>
<h3>{{$lbl_rating}}</h3>