Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Haakon Meland Eriksen 2015-08-19 19:40:18 +02:00
commit e50e687191
45 changed files with 22625 additions and 13639 deletions

View File

@ -37,6 +37,3 @@ Possible website applications include
* dating websites
* pretty much anything you can do on a traditional blog or community website, but that you could do better if you could easily connect it with other websites or privately share things across website boundaries.
This project is under development and is not yet available for general use.

View File

@ -7,12 +7,12 @@
/**
* Hubzilla.
*
* The Hubzilla (aka "Red") is an open source decentralised communications
* Hubzilla is an open source decentralised communications
* platform combined with a decentralised identity/authentication framework
* wrapped in an extensible content management system, providing website designers
* the ability to embed fully decentralised communications and social tools
* into many traditional website designs (blogs, forums, small business
* websites, charitable organisations, etc.). Red also provides DNS mobility
* websites, charitable organisations, etc.). Hubzilla also provides DNS mobility
* and internet scale privacy/access control.
*
* This allows any individual website to participate in a matrix of linked
@ -46,10 +46,10 @@ require_once('include/account.php');
define ( 'PLATFORM_NAME', 'hubzilla' );
define ( 'RED_VERSION', trim(file_get_contents('version.inc')) . 'R');
define ( 'RED_VERSION', trim(file_get_contents('version.inc')) . 'H');
define ( 'ZOT_REVISION', 1 );
define ( 'DB_UPDATE_VERSION', 1145 );
define ( 'DB_UPDATE_VERSION', 1147 );
/**
* @brief Constant with a HTML line break.
@ -717,7 +717,6 @@ class App {
set_include_path(
'include' . PATH_SEPARATOR
. 'library' . PATH_SEPARATOR
. 'library/phpsec' . PATH_SEPARATOR
. 'library/langdet' . PATH_SEPARATOR
. '.' );
@ -1056,18 +1055,7 @@ class App {
}
function set_template_engine($engine = 'smarty3') {
$this->theme['template_engine'] = $engine;
/*if ($engine) {
case 'smarty3':
if(!is_writable(TEMPLATE_BUILD_PATH))
echo "<b>ERROR</b> folder <tt>" . TEMPLATE_BUILD_PATH . "</tt> must be writable by webserver."; killme();
break;
default:
break;
}*/
}
function get_template_ldelim($engine = 'smarty3') {
@ -2271,7 +2259,7 @@ function cert_bad_email() {
'$error' => t('Website SSL certificate is not valid. Please correct.')
));
$subject = email_header_encode(sprintf(t('[red] Website SSL error for %s'), $a->get_hostname()));
$subject = email_header_encode(sprintf(t('[hubzilla] Website SSL error for %s'), $a->get_hostname()));
mail($a->config['system']['admin_email'], $subject, $email_msg,
'From: Administrator' . '@' . $a->get_hostname() . "\n"
. 'Content-type: text/plain; charset=UTF-8' . "\n"
@ -2312,7 +2300,7 @@ function check_cron_broken() {
'$lastdate' => (($d)? $d : t('never'))
));
$subject = email_header_encode(sprintf(t('[red] Cron tasks not running on %s'), $a->get_hostname()));
$subject = email_header_encode(sprintf(t('[hubzilla] Cron tasks not running on %s'), $a->get_hostname()));
mail($a->config['system']['admin_email'], $subject, $email_msg,
'From: Administrator' . '@' . $a->get_hostname() . "\n"
. 'Content-type: text/plain; charset=UTF-8' . "\n"

View File

@ -1,7 +1,7 @@
$Projectname History
====================
Redmatrix History
=================
$Projectname is a collaborative effort by the $Projectname community and based on work introduced in Friendica by the Friendica community. The core design, the project mission, and software base itself were created/written primarily by Mike Macgirvin and represent the culmination of over a decade of software design using variations of this platform and an evolving vision of the role of communication software in our lives. Many others have contributed to this work, both conceptually and in terms of actual code (way too many to list individually).
Redmatrix is a collaborative effort by the Redmatrix community and based on work introduced in Friendica by the Friendica community. The core design, the project mission, and software base itself were created/written primarily by Mike Macgirvin and represent the culmination of over a decade of software design using variations of this platform and an evolving vision of the role of communication software in our lives. Many others have contributed to this work, both conceptually and in terms of actual code (way too many to list individually).
##Mike Macgirvin -- Biography
@ -10,9 +10,9 @@ Mike Macgirvin is an American software engineer now living in Australia. He spen
During a layoff round, Mike was let go from America Online in August 2001 and purchased a music store in Mountain View, California later to be known as "Sonica Music Company". Opening a retail store for non-essential goods at the beginning of a prolonged economic downturn was in retrospect probably not the wisest career move. Sonica eventually folded; in late 2006. Mike returned to working on software and systems support full-time and was employed briefly at Symantec before moving to Australia in early 2007. He currently lives on a farm "out in the middle of nowhere" and is employed as a Computer Systems Officer at the University of Wollongong.
##$Projectname - The Early Years
##Redmatrix - The Early Years
The software which went into creating $Projectname has been through three distinct historical phases. It began in 2003 when Mike Macgirvin was looking for a content management system to power the website for his music store and found the available solutions to be lacking in various respects. The project was born as the "PurpleHaze weblog" under the nom de plume "Nerdware Communications". It was a multi-user PHP/MySQL CMS which provided blogs, forums, photo albums, events and more. Initially it provided the basis for a social community and shopping for customers of the store, but was also linked to Mike's personal weblog running on another domain. The distinguishing characteristic of this software was the ability for so-called "normal users" to re-assemble the components and choose different content feeds - and in essence create their own personal "multi-user CMS" as a view. Their custom view was able to communicate with anybody else that used the system, but could be partitioned so that adult sites and motorcycle enthusiast sites would not be visible to each other and not clash (or in this case Mike's personal website and the music store website). This software was developed primarily from 2003 until 2008.
The software which went into creating Redmatrix has been through three distinct historical phases. It began in 2003 when Mike Macgirvin was looking for a content management system to power the website for his music store and found the available solutions to be lacking in various respects. The project was born as the "PurpleHaze weblog" under the nom de plume "Nerdware Communications". It was a multi-user PHP/MySQL CMS which provided blogs, forums, photo albums, events and more. Initially it provided the basis for a social community and shopping for customers of the store, but was also linked to Mike's personal weblog running on another domain. The distinguishing characteristic of this software was the ability for so-called "normal users" to re-assemble the components and choose different content feeds - and in essence create their own personal "multi-user CMS" as a view. Their custom view was able to communicate with anybody else that used the system, but could be partitioned so that adult sites and motorcycle enthusiast sites would not be visible to each other and not clash (or in this case Mike's personal website and the music store website). This software was developed primarily from 2003 until 2008.
In 2006 this software was used as the prototype for Symantec's "safeweb" reputation and community site. It was developed and enhanced until about 2008. A rewrite took place in 2008 named "Reflection" but work stagnated as the community dwindled. The need for content management systems and communications software dropped dramatically during this time as humans flocked to the new social aggregrators - Facebook and Twitter.
@ -32,19 +32,19 @@ Mike realised he did not want to be held hostage to the decisions that other pro
Mike had been working on this project for some time and there were a number of things which needed re-writing, including the base communication protocol which Friendica used (DFRN or the "Distributed Friends and Relations Network" protocol). These ideas were starting to emerge as a different method of communication he called "zot". Zot began as a way to create a common language for federated websites, but there was no interest in this ability and as mentioned, the federated web was crumbling. The first version was soon scrapped and zot was re-designed and re-ignited as a streamlined communication protocol which was location-independent; e.g. not tied to any website. This would allow people to carry on unaffected if their website operator shut down temporarily or permanently. They wouldn't have to make friends all over again, and permissions of everything on the system wouldn't have to be changed to allow bob@site1 to see something that was private to him, even though he was now bob@site2. This was a serious problem with decentralisation. People moved and their online identities were lost and had to be re-created from scratch and existing relationships destroyed and had to be created all over again.
##$Projectname
##Redmatrix
In July 2012, Mike left the Friendica project and began development of "zot" and a new base project called "red" in his somewhat elusive *spare time*. Red is Spanish for "network". It wasn't really a "social network" and especially not a "federated social network". It was just Red (technically "la red"), or "the network". Work began by removing all the "federation" components and going back to basics - communication and remote authentication. It was a major re-write and took roughly six months before even basic communication was re-established. It was also no longer compatible with Friendica - which had been given to the "Friendica community" and by this time (December 2012) was developing separately on its own track.
It became clear during this time that the single most compelling feature of the project wasn't the social network at all, but the authentication layer and decentralised access control mechanisms. Combined with zot's location independence it created a new model for software which had never existed previously - decentralised identity-aware web publishing and single sign-on to any compatible provider across the web. These weren't *evolutionary*, they were **revolutionary**. One of the biggest flaws of the modern web is the reliance on different passwords for every service you use, or reliance on a single provider if you were to tie them to - say your Facebook login. Facebook can remove your account at any time. Gone. If you rely on their authentication for all your websites, your entire online identity - now gone. This is also what was missing from Friendica - a compelling software feature which could stand on its own, without requiring a social network and especially without requiring a federated social network with all the mentioned external dependencies.
An early visitor to the project noted that he had some difficulty finding the project on Google because of the choice of name - "red". Yes, this was a poor decision in retrospect. We were buried on page 23,712 of the search results. The concept that was emerging around this identity-aware publishing was that of "a matrix of inter-connected thought streams", since we didn't have a concept of "people" and "friends". All were just connected "channels" with different ways to connect. So "$Projectname" was chosen to give it a searchable name. It had nothing to do with the Matrix film and red and blue pills, though that is frequently cited (erronously); and in fact isn't a bad analogy.
An early visitor to the project noted that he had some difficulty finding the project on Google because of the choice of name - "red". Yes, this was a poor decision in retrospect. We were buried on page 23,712 of the search results. The concept that was emerging around this identity-aware publishing was that of "a matrix of inter-connected thought streams", since we didn't have a concept of "people" and "friends". All were just connected "channels" with different ways to connect. So "Redmatrix" was chosen to give it a searchable name. It had nothing to do with the Matrix film and red and blue pills, though that is frequently cited (erronously); and in fact isn't a bad analogy.
The concept of identity-aware content was alien to anything that existed previously on the web, so to make it useful we had to provide the ability to use it for content. It needed content publishing tools. This brought back concepts from the old "Content Management System" on which the software was originally based. To get it up and running quickly we created a markup language for webpages called "Comanche" which let you describe a page in high-level terms based on bbcode tags. We also added WebDAV so you could put decentralised access control on files and drag/drop from your operating system. So now you could have private photos, webpages, files, events, conversations, chatrooms - and they are visible to those you choose - no matter what site they use. All they need is zot. And your viewers could move to another site or just pop up at a different site any time they want and we don't care. And it **also** had a built-in social network; with lots of additional privacy and encryption features which were added even before the Snowden revelations gave them added urgency.
Over time a few federation components re-emerged. The ability to view RSS feeds was important to many people. Diaspora never really managed to re-write their protocol, so that was re-implemented and allowed $Projectname to connect with Diaspora and Friendica again (Friendica still had their Diaspora protocol intact, so this was the most common language now remaining on the free web - despite its faults). Diaspora communications aren't able to make use of the advanced identity features, but they work for basic communications.
Over time a few federation components re-emerged. The ability to view RSS feeds was important to many people. Diaspora never really managed to re-write their protocol, so that was re-implemented and allowed Redmatrix to connect with Diaspora and Friendica again (Friendica still had their Diaspora protocol intact, so this was the most common language now remaining on the free web - despite its faults). Diaspora communications aren't able to make use of the advanced identity features, but they work for basic communications.
Mike stepped down as active coordinator for the project in early 2015.
Mike resigned from the project as an active coordinator in early 2015.
#include doc/macros/main_footer.bb;

View File

@ -1,14 +1,14 @@
[zrl=[baseurl]/help/about][b]What is the $Projectname?[/b][/zrl]
[zrl=[baseurl]/help/about][b]What is $Projectname?[/b][/zrl]
$Projectname is a decentralized communication and publishing platform that enables you to keep in control of your communication needs by automatic encryption and finely grained access control. It's you, and only you who decides who is allowed to see your stuff.
[zrl=[baseurl]/help/features][b]$Projectname Features[/b][/zrl]
The $Projectname is already running as a global distributed network and proves its versatility and scalability from standalone to huge sites on a daily basis.
$Projectname is already running as a global distributed network and proves its versatility and scalability from standalone to huge sites on a daily basis.
Think of standalone family communication platforms, distributed online communities, support forums, blogs and homepages. Or professional content providers with commercial premium channels and targeted content acces. Whatever you want, the $Projectname is there to cater to your creativity.
[zrl=[baseurl]/help/what_is_zot][b]Got Zot? Well, you should.[/b][/zrl]
Zot is the great new communicaton protocol invented especially for the $Projectname. As a member you are no longer bound to a single site or hub thanks to "Nomadic Identities". Migrate easily to another server and keep your contacts intact, or clone it and run the same channel on several servers. Just in case one of them might shut down, you don't lose out. Plus once you are inside the $Projectname there is no need for you to authenticate twice, even when accessing another $Projectname site. Zot is what sets the $Projectname apart.
Zot is the great new communicaton protocol invented especially for $Projectname. As a member you are no longer bound to a single site or hub thanks to "Nomadic Identities". Migrate easily to another server and keep your contacts intact, or clone it and run the same channel on several servers. Just in case one of them might shut down, you don't lose out. Plus once you are inside $Projectname there is no need for you to authenticate twice, even when accessing another $Projectname site. Zot is what sets $Projectname apart.
[h3]Getting Started[/h3]
[zrl=[baseurl]/help/Privacy]Privacy Policy[/zrl]

View File

@ -4,10 +4,10 @@ We need much more than this, but here are areas where developers can help. Pleas
[li]Documentation - see Red Documentation Project To-Do List[/li]
[li]Include TOS link in registration/verification email[/li]
[li]forum widget with unread counts (requires the DB schema changes from v3/hubzilla to be viable)[/li]
[li](done) forum widget with unread counts (requires the DB schema changes from v3/hubzilla to be viable)[/li]
[li]Create bug tracker module[/li]
[li]translation plugins - moses or apertium[/li]
[li]Infinite scroll improvements (i.e. embedded page links) see http://scrollsample.appspot.com/items
[li]Infinite scroll improvements (i.e. embedded page links) see http://scrollsample.appspot.com/items [/li]
[li]Finish the anti-spam bayesian engine[/li]
[li]implement an email permission denied bounce message from the sys channel[/li]
[li]provide a way for xchans with a certain network type to upgrade (unknown to rss, rss to statusnet, friendica-over-diaspora to friendica, for instance) based on new knowledge and/or redmatrix ability[/li]
@ -15,7 +15,7 @@ We need much more than this, but here are areas where developers can help. Pleas
[li]Integrate the &quot;open site&quot; list with the register page[/li]
[li]implement oembed provider interface[/li]
[li]refactor the oembed client interface so that we can safely sandbox remote content[/li]
[li]Many modern social apps now have both a profile photo and a "cover photo". Add support for this.
[li]Many modern social apps now have both a profile photo and a "cover photo". Add support for this. [/li]
[li]Write more webpage layouts[/li]
[li]Write more webpage widgets[/li]
[li]restricted access OAuth clients[/li]

View File

@ -214,6 +214,29 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
$f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $hash;
$direct = null;
if($this->folder_hash) {
$r = q("select * from attach where hash = '%s' and is_dir = 1 and uid = %d limit 1",
dbesc($this->folder_hash),
intval($c[0]['channel_id'])
);
if($r)
$direct = $r[0];
}
if(($direct) && (($direct['allow_cid']) || ($direct['allow_gid']) || ($direct['deny_cid']) || ($direct['deny_gid']))) {
$allow_cid = $direct['allow_cid'];
$allow_gid = $direct['allow_gid'];
$deny_cid = $direct['deny_cid'];
$deny_gid = $direct['deny_gid'];
}
else {
$allow_cid = $c[0]['channel_allow_cid'];
$allow_gid = $c[0]['channel_allow_gid'];
$deny_cid = $c[0]['channel_deny_cid'];
$deny_gid = $c[0]['channel_deny_gid'];
}
$r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, folder, os_storage, filetype, filesize, revision, is_photo, data, created, edited, allow_cid, allow_gid, deny_cid, deny_gid )
VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ",
@ -231,10 +254,10 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
dbesc($this->os_path . '/' . $hash),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
dbesc($c[0]['channel_allow_cid']),
dbesc($c[0]['channel_allow_gid']),
dbesc($c[0]['channel_deny_cid']),
dbesc($c[0]['channel_deny_gid'])
dbesc($allow_cid),
dbesc($allow_gid),
dbesc($deny_cid),
dbesc($deny_gid)
);
@ -308,7 +331,7 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota {
}
require_once('include/photos.php');
$args = array( 'resource_id' => $hash, 'album' => $album, 'os_path' => $f, 'filename' => $name, 'getimagesize' => $x);
$args = array( 'resource_id' => $hash, 'album' => $album, 'os_path' => $f, 'filename' => $name, 'getimagesize' => $x, 'directory' => $direct);
$p = photo_upload($c[0],get_app()->get_observer(),$args);
}

View File

@ -116,12 +116,14 @@ class RedFile extends DAV\Node implements DAV\IFile {
);
if($d) {
if($d[0]['folder']) {
$f1 = q("select filename from attach where is_dir = 1 and hash = '%s' and uid = %d limit 1",
$f1 = q("select * from attach where is_dir = 1 and hash = '%s' and uid = %d limit 1",
dbesc($d[0]['folder']),
intval($c[0]['channel_id'])
);
if($f1)
if($f1) {
$album = $f1[0]['filename'];
$direct = $f1[0];
}
}
$fname = dbunescbin($d[0]['data']);
$f = 'store/' . $this->auth->owner_nick . '/' . (($fname) ? $fname : '');
@ -166,7 +168,7 @@ class RedFile extends DAV\Node implements DAV\IFile {
if($is_photo) {
require_once('include/photos.php');
$args = array( 'resource_id' => $this->data['hash'], 'album' => $album, 'os_path' => $f, 'filename' => $r[0]['filename'], 'getimagesize' => $gis );
$args = array( 'resource_id' => $this->data['hash'], 'album' => $album, 'os_path' => $f, 'filename' => $r[0]['filename'], 'getimagesize' => $gis, 'directory' => $direct );
$p = photo_upload($c[0],get_app()->get_observer(),$args);
}

View File

@ -378,6 +378,29 @@ function attach_by_hash_nodata($hash, $rev = 0) {
* @param string $options (optional) one of update, replace, revision
* @param array $arr (optional) associative array
*/
/**
* A lot going on in this function, and some of it is old cruft and some is new cruft
* and the entire thing probably needs to be refactored. It started out just storing
* files, before we had DAV. It was made extensible to do extra stuff like edit an
* existing file or optionally store a separate revision using $options to choose between different
* storage models. Along the way we moved from
* DB data storage to file system storage.
* Then DAV came along and used different upload methods depending on whether the
* file was stored as a DAV directory object or updated as a file object. One of these
* is essentially an update and the other is basically an upload, but doesn't use the traditional PHP
* upload workflow.
* Then came hubzilla and we tried to merge photo functionality with the file storage. Most of
* that integration occurs within this function.
* This required overlap with the old photo_upload stuff and photo albums were
* completely different concepts from directories which needed to be reconciled somehow.
* The old revision stuff is kind of orphaned currently. There's new revision stuff for photos
* which attaches (2) etc. onto the name, but doesn't integrate with the attach table revisioning.
* That's where it sits currently. I repeat it needs to be refactored, and this note is here
* for future explorers and those who may be doing that work to understand where it came
* from and got to be the monstrosity of tangled unrelated code that it currently is.
*/
function attach_store($channel, $observer_hash, $options = '', $arr = null) {
require_once('include/photos.php');
@ -487,9 +510,18 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
$darr['deny_gid'] = $channel['deny_gid'];
$direct = null;
if($pathname) {
$x = attach_mkdirp($channel, $observer_hash, $darr);
$folder_hash = (($x['success']) ? $x['data']['hash'] : '');
$direct = (($x['success']) ? $x['data'] : null);
if((! $str_contact_allow) && (! $str_group_allow) && (! $str_contact_deny) && (! $str_group_deny)) {
$str_contact_allow = $x['data']['allow_cid'];
$str_group_allow = $x['data']['allow_gid'];
$str_contact_deny = $x['data']['deny_cid'];
$str_group_deny = $x['data']['deny_gid'];
}
}
else {
$folder_hash = '';
@ -663,7 +695,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) {
}
if($is_photo) {
$args = array( 'source' => $source, 'visible' => 0, 'resource_id' => $hash, 'album' => basename($pathname), 'os_path' => $os_basepath . $os_relpath, 'filename' => $filename, 'getimagesize' => $gis);
$args = array( 'source' => $source, 'visible' => 0, 'resource_id' => $hash, 'album' => basename($pathname), 'os_path' => $os_basepath . $os_relpath, 'filename' => $filename, 'getimagesize' => $gis, 'directory' => $direct);
if($arr['contact_allow'])
$args['contact_allow'] = $arr['contact_allow'];
if($arr['group_allow'])
@ -809,7 +841,7 @@ function attach_mkdir($channel, $observer_hash, $arr = null) {
// Check for duplicate name.
// Check both the filename and the hash as we will be making use of both.
$r = q("select hash, is_dir, flags from attach where ( filename = '%s' or hash = '%s' ) and folder = '%s' and uid = %d limit 1",
$r = q("select id, hash, is_dir, flags from attach where ( filename = '%s' or hash = '%s' ) and folder = '%s' and uid = %d limit 1",
dbesc($arr['filename']),
dbesc($arr['hash']),
dbesc($arr['folder']),
@ -817,8 +849,12 @@ function attach_mkdir($channel, $observer_hash, $arr = null) {
);
if($r) {
if(array_key_exists('force',$arr) && intval($arr['force'])
&& ( intval($r[0]['is_dir']) || $r[0]['flags'] & ATTACH_FLAG_DIR)) {
&& (intval($r[0]['is_dir']))) {
$ret['success'] = true;
$r = q("select * from attach where id = %d limit 1",
intval($r[0]['id'])
);
if($r)
$ret['data'] = $r[0];
return $ret;
}
@ -886,7 +922,6 @@ function attach_mkdir($channel, $observer_hash, $arr = null) {
if($r) {
if(os_mkdir($path, STORAGE_DEFAULT_PERMISSIONS, true)) {
$ret['success'] = true;
$ret['data'] = $arr;
// update the parent folder's lastmodified timestamp
$e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d",
@ -894,6 +929,13 @@ function attach_mkdir($channel, $observer_hash, $arr = null) {
dbesc($arr['folder']),
intval($channel_id)
);
$z = q("select * from attach where hash = '%s' and uid = %d and is_dir = 1 limit 1",
dbesc($arr['hash']),
intval($channel_id)
);
if($z)
$ret['data'] = $z[0];
}
else {
logger('attach_mkdir: ' . mkdir . ' ' . $path . ' failed.');

View File

@ -1597,7 +1597,7 @@ function profile_tabs($a, $is_owner = false, $nickname = null){
);
$tabs[] = array(
'label' => t('Files'),
'url' => $a->get_baseurl() . '/cloud/' . $nickname . ((get_observer_hash()) ? '' : '?f=&davguest=1'),
'url' => $a->get_baseurl() . '/cloud/' . $nickname,
'sel' => ((argv(0) == 'cloud' || argv(0) == 'sharedwithme') ? 'active' : ''),
'title' => t('Files and Storage'),
'id' => 'files-tab',

View File

@ -80,9 +80,16 @@ function ical_wrapper($ev) {
function format_event_ical($ev) {
if($ev['type'] === 'task')
return format_todo_ical($ev);
$o = '';
$o .= "\nBEGIN:VEVENT";
$o .= "\nCREATED:" . datetime_convert('UTC','UTC', $ev['created'],'Ymd\\THis\\Z');
$o .= "\nLAST-MODIFIED:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z');
$o .= "\nDTSTAMP:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z');
if($ev['start'])
$o .= "\nDTSTART:" . datetime_convert('UTC','UTC', $ev['start'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
if($ev['finish'] && ! $ev['nofinish'])
@ -100,6 +107,41 @@ function format_event_ical($ev) {
}
function format_todo_ical($ev) {
$o = '';
$o .= "\nBEGIN:VTODO";
$o .= "\nCREATED:" . datetime_convert('UTC','UTC', $ev['created'],'Ymd\\THis\\Z');
$o .= "\nLAST-MODIFIED:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z');
$o .= "\nDTSTAMP:" . datetime_convert('UTC','UTC', $ev['edited'],'Ymd\\THis\\Z');
if($ev['start'])
$o .= "\nDTSTART:" . datetime_convert('UTC','UTC', $ev['start'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
if($ev['finish'] && ! $ev['nofinish'])
$o .= "\nDUE:" . datetime_convert('UTC','UTC', $ev['finish'],'Ymd\\THis' . (($ev['adjust']) ? '\\Z' : ''));
if($ev['summary'])
$o .= "\nSUMMARY:" . format_ical_text($ev['summary']);
if($ev['event_status']) {
$o .= "\nSTATUS:" . $ev['event_status'];
if($ev['event_status'] === 'COMPLETED')
$o .= "\nCOMPLETED:" . datetime_convert('UTC','UTC', $ev['event_status_date'],'Ymd\\THis\\Z');
}
if(intval($ev['event_percent']))
$o .= "\nPERCENT-COMPLETE:" . $ev['event_percent'];
if(intval($ev['event_sequence']))
$o .= "\nSEQUENCE:" . $ev['event_sequence'];
if($ev['location'])
$o .= "\nLOCATION:" . format_ical_text($ev['location']);
if($ev['description'])
$o .= "\nDESCRIPTION:" . format_ical_text($ev['description']);
$o .= "\nUID:" . $ev['event_hash'] ;
$o .= "\nEND:VTODO\n";
return $o;
}
function format_ical_text($s) {
require_once('include/bbcode.php');
require_once('include/html2plain.php');
@ -224,6 +266,11 @@ function event_store_event($arr) {
$arr['event_xchan'] = (($arr['event_xchan']) ? $arr['event_xchan'] : '');
if(array_key_exists('event_status_date',$arr))
$arr['event_status_date'] = datetime_convert('UTC','UTC', $arr['event_status_date']);
else
$arr['event_status_date'] = NULL_DATE;
// Existing event being modified
if($arr['id'] || $arr['event_hash']) {
@ -265,6 +312,11 @@ function event_store_event($arr) {
`type` = '%s',
`adjust` = %d,
`nofinish` = %d,
`event_status` = '%s',
`event_status_date` = '%s',
`event_percent` = %d,
`event_repeat` = '%s',
`event_sequence` = %d,
`allow_cid` = '%s',
`allow_gid` = '%s',
`deny_cid` = '%s',
@ -280,6 +332,11 @@ function event_store_event($arr) {
dbesc($arr['type']),
intval($arr['adjust']),
intval($arr['nofinish']),
dbesc($arr['event_status']),
dbesc($arr['event_status_date']),
intval($arr['event_percent']),
dbesc($arr['event_repeat']),
intval($arr['event_sequence']),
dbesc($arr['allow_cid']),
dbesc($arr['allow_gid']),
dbesc($arr['deny_cid']),
@ -298,8 +355,8 @@ function event_store_event($arr) {
$hash = random_string() . '@' . get_app()->get_hostname();
$r = q("INSERT INTO event ( uid,aid,event_xchan,event_hash,created,edited,start,finish,summary,description,location,type,
adjust,nofinish,allow_cid,allow_gid,deny_cid,deny_gid)
VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s' ) ",
adjust,nofinish, event_status, event_status_date, event_percent, event_repeat, event_sequence, allow_cid,allow_gid,deny_cid,deny_gid)
VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', %d, '%s', %d, '%s', '%s', '%s', '%s' ) ",
intval($arr['uid']),
intval($arr['account']),
dbesc($arr['event_xchan']),
@ -314,6 +371,11 @@ function event_store_event($arr) {
dbesc($arr['type']),
intval($arr['adjust']),
intval($arr['nofinish']),
dbesc($arr['event_status']),
dbesc($arr['event_status_date']),
intval($arr['event_percent']),
dbesc($arr['event_repeat']),
intval($arr['event_sequence']),
dbesc($arr['allow_cid']),
dbesc($arr['allow_gid']),
dbesc($arr['deny_cid']),
@ -399,9 +461,15 @@ require_once('vendor/autoload.php');
$ical = VObject\Reader::read($s);
if($ical) {
if($ical->VEVENT) {
foreach($ical->VEVENT as $event) {
event_import_ical($event,$uid);
}
}
if($ical->VTODO) {
foreach($ical->VTODO as $event) {
event_import_ical_task($event,$uid);
}
}
}
@ -507,6 +575,136 @@ function event_import_ical($ical, $uid) {
}
function event_import_ical_task($ical, $uid) {
$c = q("select * from channel where channel_id = %d limit 1",
intval($uid)
);
if(! $c)
return false;
$channel = $c[0];
$ev = array();
if(! isset($ical->DTSTART)) {
logger('no event start');
return false;
}
$dtstart = $ical->DTSTART->getDateTime();
// logger('dtstart: ' . var_export($dtstart,true));
if(($dtstart->timezone_type == 2) || (($dtstart->timezone_type == 3) && ($dtstart->timezone === 'UTC'))) {
$ev['adjust'] = 1;
}
else {
$ev['adjust'] = 0;
}
$ev['start'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),'UTC',
$dtstart->format(\DateTime::W3C));
if(isset($ical->DUE)) {
$dtend = $ical->DUE->getDateTime();
$ev['finish'] = datetime_convert((($ev['adjust']) ? 'UTC' : date_default_timezone_get()),'UTC',
$dtend->format(\DateTime::W3C));
}
else
$ev['nofinish'] = 1;
if($ev['start'] === $ev['finish'])
$ev['nofinish'] = 1;
if(isset($ical->CREATED)) {
$created = $ical->CREATED->getDateTime();
$ev['created'] = datetime_convert('UTC','UTC',$created->format(\DateTime::W3C));
}
if(isset($ical->{'DTSTAMP'})) {
$edited = $ical->{'DTSTAMP'}->getDateTime();
$ev['edited'] = datetime_convert('UTC','UTC',$edited->format(\DateTime::W3C));
}
if(isset($ical->{'LAST-MODIFIED'})) {
$edited = $ical->{'LAST-MODIFIED'}->getDateTime();
$ev['edited'] = datetime_convert('UTC','UTC',$edited->format(\DateTime::W3C));
}
if(isset($ical->LOCATION))
$ev['location'] = (string) $ical->LOCATION;
if(isset($ical->DESCRIPTION))
$ev['description'] = (string) $ical->DESCRIPTION;
if(isset($ical->SUMMARY))
$ev['summary'] = (string) $ical->SUMMARY;
$stored_event = null;
if(isset($ical->UID)) {
$evuid = (string) $ical->UID;
$r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
dbesc($evuid),
intval($uid)
);
if($r) {
$ev['event_hash'] = $evuid;
$stored_event = $r[0];
}
else {
$ev['external_id'] = $evuid;
}
}
if(isset($ical->SEQUENCE)) {
$ev['event_sequence'] = (string) $ical->SEQUENCE;
// see if our stored event is more current than the one we're importing
if((intval($ev['event_sequence']) <= intval($stored_event['event_sequence']))
&& ($ev['edited'] <= $stored_event['edited']))
return false;
}
if(isset($ical->STATUS)) {
$ev['event_status'] = (string) $ical->STATUS;
}
if(isset($ical->{'COMPLETED'})) {
$completed = $ical->{'COMPLETED'}->getDateTime();
$ev['event_status_date'] = datetime_convert('UTC','UTC',$completed->format(\DateTime::W3C));
}
if(isset($ical->{'PERCENT-COMPLETE'})) {
$ev['event_percent'] = (string) $ical->{'PERCENT-COMPLETE'} ;
}
$ev['type'] = 'task';
if($ev['summary'] && $ev['start']) {
$ev['event_xchan'] = $channel['channel_hash'];
$ev['uid'] = $channel['channel_id'];
$ev['account'] = $channel['channel_account_id'];
$ev['private'] = 1;
$ev['allow_cid'] = '<' . $channel['channel_hash'] . '>';
logger('storing event: ' . print_r($ev,true), LOGGER_ALL);
$event = event_store_event($ev);
if($event) {
$item_id = event_store_item($ev,$event);
return true;
}
}
return false;
}
function event_store_item($arr, $event) {
@ -698,3 +896,14 @@ function event_store_item($arr, $event) {
return $item_id;
}
}
function todo_stat() {
return array(
'' => t('Not specified'),
'NEEDS-ACTION' => t('Needs Action'),
'COMPLETED' => t('Completed'),
'IN-PROCESS' => t('In Process'),
'CANCELLED' => t('Cancelled')
);
}

View File

@ -604,15 +604,27 @@ function identity_basic_export($channel_id, $items = false) {
}
function identity_export_year($channel_id,$year) {
function identity_export_year($channel_id,$year,$month = 0) {
if(! $year)
return array();
if($month && $month <= 12) {
$target_month = sprintf('%02d',$month);
$target_month_plus = sprintf('%02d',$month+1);
}
else
$target_month = '01';
$ret = array();
$mindate = datetime_convert('UTC','UTC',$year . '-01-01 00:00:00');
$mindate = datetime_convert('UTC','UTC',$year . '-' . $target_month . '-01 00:00:00');
if($month && $month < 12)
$maxdate = datetime_convert('UTC','UTC',$year . '-' . $target_month_plus . '-01 00:00:00');
else
$maxdate = datetime_convert('UTC','UTC',$year+1 . '-01-01 00:00:00');
$r = q("select * from item where item_wall = 1 and item_deleted = 0 and uid = %d and created >= '%s' and created < '%s' ",
$r = q("select * from item where item_wall = 1 and item_deleted = 0 and uid = %d and created >= '%s' and created < '%s' order by created",
intval($channel_id),
dbesc($mindate),
dbesc($maxdate)
@ -626,6 +638,18 @@ function identity_export_year($channel_id,$year) {
$ret['item'][] = encode_item($rr,true);
}
$r = q("select item_id.*, item.mid from item_id left join item on item_id.iid = item.id where item_id.uid = %d
and item.created >= '%s' and item.created < '%s' order by created ",
intval($channel_id),
dbesc($mindate),
dbesc($maxdate)
);
if($r)
$ret['item_id'] = $r;
return $ret;
}

View File

@ -495,6 +495,32 @@ function post_activity_item($arr) {
return $ret;
}
function validate_item_elements($message,$arr) {
$result = array('success' => false);
if(! array_key_exists('created',$arr))
$result['message'] = 'missing created, possible author/owner lookup failure';
if((! $arr['mid']) || (! $arr['parent_mid']))
$result['message'] = 'missing message-id or parent message-id';
if(array_key_exists('flags',$message) && in_array('relay',$message['flags']) && $arr['mid'] === $arr['parent_mid'])
$result['message'] = 'relay set on top level post';
if(! $result['message'])
$result['success'] = true;
return $result;
}
/**
* @brief Generate an Atom feed.
*
@ -866,7 +892,11 @@ function get_item_elements($x) {
$arr['sig'] = (($x['signature']) ? htmlspecialchars($x['signature'], ENT_COMPAT,'UTF-8',false) : '');
if(array_key_exists('diaspora_signature',$x) && is_array($x['diaspora_signature']))
$x['diaspora_signature'] = json_encode($x['diaspora_signature']);
$arr['diaspora_meta'] = (($x['diaspora_signature']) ? $x['diaspora_signature'] : '');
$arr['object'] = activity_sanitise($x['object']);
$arr['target'] = activity_sanitise($x['target']);
@ -1581,12 +1611,10 @@ function get_mail_elements($x) {
$arr['mail_obscured'] = 1;
if($arr['body']) {
$arr['body'] = str_rot47(base64url_encode($arr['body']));
$arr['body'] = htmlspecialchars($arr['body'],ENT_COMPAT,'UTF-8',false);
}
if($arr['title']) {
$arr['title'] = str_rot47(base64url_encode($arr['title']));
$arr['title'] = htmlspecialchars($arr['title'],ENT_COMPAT,'UTF-8',false);
}
if($arr['created'] > datetime_convert())
$arr['created'] = datetime_convert();
@ -3450,8 +3478,10 @@ function mail_store($arr) {
return 0;
}
if(! $arr['mail_obscured']) {
if((strpos($arr['body'],'<') !== false) || (strpos($arr['body'],'>') !== false))
$arr['body'] = escape_tags($arr['body']);
}
if(array_key_exists('attach',$arr) && is_array($arr['attach']))
$arr['attach'] = json_encode($arr['attach']);

View File

@ -170,11 +170,11 @@ function send_message($uid = 0, $recipient='', $body='', $subject='', $replyto='
$r = q("INSERT INTO mail ( account_id, convid, mail_flags, channel_id, from_xchan, to_xchan, title, body, attach, mid, parent_mid, created, expires )
$r = q("INSERT INTO mail ( account_id, convid, mail_obscured, channel_id, from_xchan, to_xchan, title, body, attach, mid, parent_mid, created, expires )
VALUES ( %d, %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )",
intval($channel['channel_account_id']),
intval($convid),
intval(MAIL_OBSCURED),
intval(1),
intval($channel['channel_id']),
dbesc($channel['channel_hash']),
dbesc($recipient),
@ -330,6 +330,7 @@ function private_messages_fetch_message($channel_id, $messageitem_id, $updatesee
}
}
if($updateseen) {
$r = q("UPDATE `mail` SET mail_seen = 1 where mail_seen = 0 and id = %d AND channel_id = %d",
dbesc($messageitem_id),
@ -416,6 +417,7 @@ function private_messages_fetch_conversation($channel_id, $messageitem_id, $upda
}
if($updateseen) {
$r = q("UPDATE `mail` SET mail_seen = 1 where mail_seen = 0 and parent_mid = '%s' AND channel_id = %d",
dbesc($r[0]['parent_mid']),

View File

@ -50,20 +50,32 @@ function photo_upload($channel, $observer, $args) {
else
$visible = 0;
// Set to default channel permissions. If the parent directory (album) has permissions set,
// use those instead. If we have specific permissions supplied, they take precedence over
// all other settings.
$str_group_allow = $channel['channel_allow_gid'];
$str_contact_allow = $channel['channel_allow_cid'];
$str_group_deny = $channel['channel_deny_gid'];
$str_contact_deny = $channel['channel_deny_cid'];
if($args['directory']) {
$str_group_allow = $args['directory']['allow_gid'];
$str_contact_allow = $args['directory']['allow_cid'];
$str_group_deny = $args['directory']['deny_gid'];
$str_contact_deny = $args['directory']['deny_cid'];
}
if( (array_key_exists('group_allow',$args))
|| (array_key_exists('contact_allow',$args))
|| (array_key_exists('group_deny',$args))
|| (array_key_exists('contact_deny',$args))) {
$str_group_allow = perms2str(((is_array($args['group_allow'])) ? $args['group_allow'] : explode(',',$args['group_allow'])));
$str_contact_allow = perms2str(((is_array($args['contact_allow'])) ? $args['contact_allow'] : explode(',',$args['contact_allow'])));
$str_group_deny = perms2str(((is_array($args['group_deny'])) ? $args['group_deny'] : explode(',',$args['group_deny'])));
$str_contact_deny = perms2str(((is_array($args['contact_deny'])) ? $args['contact_deny'] : explode(',',$args['contact_deny'])));
if( (! array_key_exists('group_allow',$args))
&& (! array_key_exists('contact_allow',$args))
&& (! array_key_exists('group_deny',$args))
&& (! array_key_exists('contact_deny',$args))) {
$str_group_allow = $channel['channel_allow_gid'];
$str_contact_allow = $channel['channel_allow_cid'];
$str_group_deny = $channel['channel_deny_gid'];
$str_contact_deny = $channel['channel_deny_cid'];
}
$os_storage = 0;

View File

@ -980,10 +980,65 @@ function widget_rating($arr) {
}
// used by site ratings pages to provide a return link
function widget_pubsites() {
function widget_pubsites($arr) {
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>';
}
function widget_forums($arr) {
$a = get_app();
if(! local_channel())
return '';
$o = '';
if(is_array($arr) && array_key_exists('limit',$arr))
$limit = " limit " . intval($limit) . " ";
else
$limit = '';
$unseen = 0;
if(is_array($arr) && array_key_exists('unseen',$arr) && intval($arr['unseen']))
$unseen = 1;
$perms_sql = item_permissions_sql(local_channel()) . item_normal();
$r1 = q("select * from abook left join xchan on abook_xchan = xchan_hash where xchan_pubforum = 1 and abook_channel = %d order by xchan_name $limit ",
intval(local_channel())
);
if(! $r1)
return $o;
$str = '';
// Trying to cram all this into a single query with joins and the proper group by's is tough.
// There also should be a way to update this via ajax.
for($x = 0; $x < count($r1); $x ++) {
$r = q("select sum(item_unseen) as unseen from item where owner_xchan = '%s' and uid = %d $perms_sql ",
dbesc($r1[$x]['xchan_hash']),
intval(local_channel())
);
if($r)
$r1[$x]['unseen'] = $r[0]['unseen'];
}
if($r1) {
$o .= '<div class="widget">';
$o .= '<h3>' . t('Forums') . '</h3><ul class="nav nav-pills nav-stacked">';
foreach($r1 as $rr) {
if($unseen && (! intval($rr['unseen'])))
continue;
$o .= '<li><span class="pull-right">' . ((intval($rr['unseen'])) ? intval($rr['unseen']) : '') . '</span><a href="network?f=&cid=' . $rr['abook_id'] . '" ><img src="' . $rr['xchan_photo_s'] . '" style="width: 16px; height: 16px;" /> ' . $rr['xchan_name'] . '</a></li>';
}
$o .= '</ul></div>';
}
return $o;
}

View File

@ -1178,8 +1178,10 @@ function zot_import($arr, $sender_url) {
if($i['message']['type'] === 'activity') {
$arr = get_item_elements($i['message']);
if(! array_key_exists('created',$arr)) {
logger('Activity rejected: probable failure to lookup author/owner. ' . print_r($i['message'],true));
$v = validate_item_elements($i['message'],$arr);
if(! $v['success']) {
logger('Activity rejected: ' . $v['message'] . ' ' . print_r($i['message'],true));
continue;
}
@ -1537,8 +1539,9 @@ function process_delivery($sender, $arr, $deliveries, $relay, $public = false, $
$tag_delivery = tgroup_check($channel['channel_id'],$arr);
$perm = (($arr['mid'] == $arr['parent_mid']) ? 'send_stream' : 'post_comments');
$perm = 'send_stream';
if(($arr['mid'] !== $arr['parent_mid']) && ($relay))
$perm = 'post_comments';
// This is our own post, possibly coming from a channel clone

View File

@ -367,6 +367,11 @@ CREATE TABLE IF NOT EXISTS `event` (
`allow_gid` mediumtext NOT NULL,
`deny_cid` mediumtext NOT NULL,
`deny_gid` mediumtext NOT NULL,
`event_status` char(255) NOT NULL DEFAULT '',
`event_status_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`event_percent` smallint(6) NOT NULL DEFAULT '0',
`event_repeat` text NOT NULL,
`event_sequence` smallint(6) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `uid` (`uid`),
KEY `type` (`type`),
@ -377,7 +382,9 @@ CREATE TABLE IF NOT EXISTS `event` (
KEY `ignore` (`ignore`),
KEY `aid` (`aid`),
KEY `event_hash` (`event_hash`),
KEY `event_xchan` (`event_xchan`)
KEY `event_xchan` (`event_xchan`),
KEY `event_status` (`event_status`),
KEY `event_sequence` (`event_sequence`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `fcontact` (

View File

@ -358,6 +358,11 @@ CREATE TABLE "event" (
"allow_gid" text NOT NULL,
"deny_cid" text NOT NULL,
"deny_gid" text NOT NULL,
"event_status" char(255) NOT NULL DEFAULT '',
"event_status_date" timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
"event_percent" smallint(6) NOT NULL DEFAULT '0',
"event_repeat" text NOT NULL,
"event_sequence" smallint NOT NULL DEFAULT '0',
PRIMARY KEY ("id")
);
create index "event_uid_idx" on event ("uid");
@ -370,6 +375,8 @@ create index "event_ignore_idx" on event ("ignore");
create index "event_aid_idx" on event ("aid");
create index "event_hash_idx" on event ("event_hash");
create index "event_xchan_idx" on event ("event_xchan");
create index "event_status_idx" on event ("event_status");
create index "event_sequence_idx" on event ("event_sequence");
CREATE TABLE "fcontact" (

View File

@ -1,6 +1,6 @@
<?php
define( 'UPDATE_VERSION' , 1145 );
define( 'UPDATE_VERSION' , 1147 );
/**
*
@ -1687,3 +1687,36 @@ function update_r1144() {
return UPDATE_SUCCESS;
}
function update_r1145() {
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
$r1 = q("ALTER TABLE event ADD event_status char(255) NOT NULL DEFAULT '',
ADD event_status_date timestamp NOT NULL DEFAULT '0001-01-01 00:00:00',
ADD event_percent SMALLINT NOT NULL DEFAULT '0',
ADD event_repeat TEXT NOT NULL DEFAULT '' ");
$r2 = q("create index event_status on event ( event_status )");
$r = $r1 && $r2;
}
else {
$r = q("ALTER TABLE `event` ADD `event_status` CHAR( 255 ) NOT NULL DEFAULT '',
ADD `event_status_date` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
ADD `event_percent` SMALLINT NOT NULL DEFAULT '0',
ADD `event_repeat` TEXT NOT NULL DEFAULT '',
ADD INDEX ( `event_status` ) ");
}
if($r)
return UPDATE_SUCCESS;
return UPDATE_FAILED;
}
function update_r1146() {
$r1 = q("alter table event add event_sequence smallint not null default '0' ");
$r2 = q("create index event_sequence on event ( event_sequence ) ");
if($r1 && $r2)
return UPDATE_SUCCESS;
return UPDATE_FAILED;
}

View File

@ -92,7 +92,7 @@ function acl_init(&$a){
if($extra_channels_sql != '')
$extra_channels_sql = " OR (abook_channel IN ($extra_channels_sql)) and abook_hidden = 0 ";
$r = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, abook_flags
$r = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, abook_flags, abook_self
FROM abook left join xchan on abook_xchan = xchan_hash
WHERE (abook_channel = %d $extra_channels_sql) AND abook_blocked = 0 and abook_pending = 0 and abook_archived = 0 and xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc" ,
intval(local_channel())
@ -100,7 +100,7 @@ function acl_init(&$a){
}
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
$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, 0 as abook_self
FROM xchan left join xlink on xlink_link = xchan_hash
WHERE xlink_xchan = '%s' AND xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc" ,
dbesc(get_observer_hash())
@ -116,7 +116,7 @@ function acl_init(&$a){
$known_hashes[] = "'".$rr['hash']."'";
$known_hashes_sql = 'AND xchan_hash not in ('.join(',',$known_hashes).')';
$r2 = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, abook_flags
$r2 = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, abook_their_perms, abook_flags, abook_self
FROM abook left join xchan on abook_xchan = xchan_hash
WHERE abook_channel IN ($extra_channels_sql) $known_hashes_sql AND abook_blocked = 0 and abook_pending = 0 and abook_archived = 0 and abook_hidden = 0 and xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc");
if($r2)
@ -145,7 +145,7 @@ function acl_init(&$a){
}
if(intval(get_config('system','taganyone')) || intval(get_pconfig(local_channel(),'system','taganyone'))) {
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
$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, 0 as abook_self
FROM xchan
WHERE xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc"
);

View File

@ -677,7 +677,7 @@ function admin_page_users_post($a) {
intval($users[$i])
);
}
notice( sprintf( tt("%s user blocked/unblocked", "%s users blocked/unblocked", count($users)), count($users)) );
notice( sprintf( tt("%s account blocked/unblocked", "%s account blocked/unblocked", count($users)), count($users)) );
}
// account delete button was submitted
if (x($_POST, 'page_users_delete')) {
@ -685,7 +685,7 @@ function admin_page_users_post($a) {
foreach ($users as $uid){
account_remove($uid, true, false);
}
notice( sprintf( tt("%s user deleted", "%s users deleted", count($users)), count($users)) );
notice( sprintf( tt("%s account deleted", "%s accounts deleted", count($users)), count($users)) );
}
// registration approved button was submitted
if (x($_POST, 'page_users_approve')) {
@ -733,7 +733,7 @@ function admin_page_users(&$a){
require_once('include/Contact.php');
account_remove($uid,true,false);
notice( sprintf(t("User '%s' deleted"), $account[0]['account_email']) . EOL);
notice( sprintf(t("Account '%s' deleted"), $account[0]['account_email']) . EOL);
break;
case 'block':
q("UPDATE account SET account_flags = ( account_flags | %d ) WHERE account_id = %d",
@ -741,7 +741,7 @@ function admin_page_users(&$a){
intval($uid)
);
notice( sprintf( t("User '%s' blocked") , $account[0]['account_email']) . EOL);
notice( sprintf( t("Account '%s' blocked") , $account[0]['account_email']) . EOL);
break;
case 'unblock':
q("UPDATE account SET account_flags = ( account_flags & ~%d ) WHERE account_id = %d",
@ -749,7 +749,7 @@ function admin_page_users(&$a){
intval($uid)
);
notice( sprintf( t("User '%s' unblocked"), $account[0]['account_email']) . EOL);
notice( sprintf( t("Account '%s' unblocked"), $account[0]['account_email']) . EOL);
break;
}
@ -826,8 +826,8 @@ function admin_page_users(&$a){
'$h_users' => t('Users'),
'$th_users' => array( t('ID'), t('Email'), t('All Channels'), t('Register date'), t('Last login'), t('Expires'), t('Service Class')),
'$confirm_delete_multi' => t('Selected users will be deleted!\n\nEverything these users had posted on this site will be permanently deleted!\n\nAre you sure?'),
'$confirm_delete' => t('The user {0} will be deleted!\n\nEverything this user has posted on this site will be permanently deleted!\n\nAre you sure?'),
'$confirm_delete_multi' => t('Selected accounts will be deleted!\n\nEverything these accounts had posted on this site will be permanently deleted!\n\nAre you sure?'),
'$confirm_delete' => t('The account {0} will be deleted!\n\nEverything this account has posted on this site will be permanently deleted!\n\nAre you sure?'),
'$form_security_token' => get_form_security_token("admin_users"),

View File

@ -437,7 +437,6 @@ function import_post(&$a) {
// FIXME - ensure we have an xchan if somebody is trying to pull a fast one
if($completed < 8) {
$friends = 0;
$feeds = 0;
@ -446,10 +445,6 @@ function import_post(&$a) {
$abooks = $data['abook'];
if($abooks) {
foreach($abooks as $abook) {
if($max_friends !== false && $friends > $max_friends)
continue;
if($max_feeds !== false && intval($abook['abook_feed']) && ($feeds > $max_feeds))
continue;
unset($abook['abook_id']);
unset($abook['abook_rating']);
@ -475,6 +470,12 @@ function import_post(&$a) {
);
}
}
else {
if($max_friends !== false && $friends > $max_friends)
continue;
if($max_feeds !== false && intval($abook['abook_feed']) && ($feeds > $max_feeds))
continue;
}
dbesc_array($abook);
$r = dbq("INSERT INTO abook (`"

172
mod/import_items.php Normal file
View File

@ -0,0 +1,172 @@
<?php
function import_items_post(&$a) {
if(! local_channel())
return;
$data = null;
$src = $_FILES['filename']['tmp_name'];
$filename = basename($_FILES['filename']['name']);
$filesize = intval($_FILES['filename']['size']);
$filetype = $_FILES['filename']['type'];
if($src) {
// This is OS specific and could also fail if your tmpdir isn't very large
// mostly used for Diaspora which exports gzipped files.
if(strpos($filename,'.gz')){
@rename($src,$src . '.gz');
@system('gunzip ' . escapeshellarg($src . '.gz'));
}
if($filesize) {
$data = @file_get_contents($src);
}
unlink($src);
}
if(! $src) {
$old_address = ((x($_REQUEST,'old_address')) ? $_REQUEST['old_address'] : '');
if(! $old_address) {
logger('mod_import: nothing to import.');
notice( t('Nothing to import.') . EOL);
return;
}
$email = ((x($_REQUEST,'email')) ? $_REQUEST['email'] : '');
$password = ((x($_REQUEST,'password')) ? $_REQUEST['password'] : '');
$year = ((x($_REQUEST,'year')) ? $_REQUEST['year'] : '');
$channelname = substr($old_address,0,strpos($old_address,'@'));
$servername = substr($old_address,strpos($old_address,'@')+1);
$scheme = 'https://';
$api_path = '/api/red/channel/export/items?f=&channel=' . $channelname . '&year=' . intval($year);
$binary = false;
$redirects = 0;
$opts = array('http_auth' => $email . ':' . $password);
$url = $scheme . $servername . $api_path;
$ret = z_fetch_url($url, $binary, $redirects, $opts);
if(! $ret['success'])
$ret = z_fetch_url('http://' . $servername . $api_path, $binary, $redirects, $opts);
if($ret['success'])
$data = $ret['body'];
else
notice( t('Unable to download data from old server') . EOL);
}
if(! $data) {
logger('mod_import: empty file.');
notice( t('Imported file is empty.') . EOL);
return;
}
$data = json_decode($data,true);
// logger('import: data: ' . print_r($data,true));
// print_r($data);
if(array_key_exists('compatibility',$data) && array_key_exists('database',$data['compatibility'])) {
$v1 = substr($data['compatibility']['database'],-4);
$v2 = substr(DB_UPDATE_VERSION,-4);
if($v2 > $v1) {
$t = sprintf( t('Warning: Database versions differ by %1$d updates.'), $v2 - $v1 );
notice($t);
}
}
$channel = $a->get_channel();
$saved_notification_flags = notifications_off($channel['channel_id']);
if(array_key_exists('item',$data) && $data['item']) {
foreach($data['item'] as $i) {
$item = get_item_elements($i);
$r = q("select id, edited from item where mid = '%s' and uid = %d limit 1",
dbesc($item['mid']),
intval($channel['channel_id'])
);
if($r) {
if($item['edited'] > $r[0]['edited']) {
$item['id'] = $r[0]['id'];
$item['uid'] = $channel['channel_id'];
item_store_update($item);
continue;
}
}
else {
$item['aid'] = $channel['channel_account_id'];
$item['uid'] = $channel['channel_id'];
$item_result = item_store($item);
}
}
}
notifications_on($channel['channel_id'],$saved_notification_flags);
if(array_key_exists('item_id',$data) && $data['item_id']) {
foreach($data['item_id'] as $i) {
$r = q("select id from item where mid = '%s' and uid = %d limit 1",
dbesc($i['mid']),
intval($channel['channel_id'])
);
if(! $r)
continue;
$z = q("select * from item_id where service = '%s' and sid = '%s' and iid = %d and uid = %d limit 1",
dbesc($i['service']),
dbesc($i['sid']),
intval($r[0]['id']),
intval($channel['channel_id'])
);
if(! $z) {
q("insert into item_id (iid,uid,sid,service) values(%d,%d,'%s','%s')",
intval($r[0]['id']),
intval($channel['channel_id']),
dbesc($i['sid']),
dbesc($i['service'])
);
}
}
}
info( t('Import completed') . EOL);
return;
}
function import_items_content(&$a) {
if(! local_channel()) {
notice( t('Permission denied') . EOL);
return login();
}
$o = replace_macros(get_markup_template('item_import.tpl'),array(
'$title' => t('Import Items'),
'$desc' => t('Use this form to import existing posts and content from an export file.'),
'$label_filename' => t('File to Upload'),
'$submit' => t('Submit')
));
return $o;
}

View File

@ -1051,6 +1051,23 @@ function fix_attached_photo_permissions($uid,$xchan_hash,$body,
continue;
$srch = '<' . $xchan_hash . '>';
$r = q("select folder from attach where hash = '%s' and uid = %d limit 1",
dbesc($image_uri),
intval($uid)
);
if($r && $r[0]['folder']) {
$f = q("select * from attach where hash = '%s' and is_dir = 1 and uid = %d limit 1",
dbesc($r[0]['folder']),
intval($uid)
);
if(($f) && (($f[0]['allow_cid']) || ($f[0]['allow_gid']) || ($f[0]['deny_cid']) || ($f[0]['deny_gid']))) {
$str_contact_allow = $f[0]['allow_cid'];
$str_group_allow = $f[0]['allow_gid'];
$str_contact_deny = $f[0]['deny_cid'];
$str_group_deny = $f[0]['deny_gid'];
}
}
$r = q("SELECT id FROM photo
WHERE allow_cid = '%s' AND allow_gid = '' AND deny_cid = '' AND deny_gid = ''
AND resource_id = '%s' AND uid = %d LIMIT 1",

View File

@ -73,9 +73,10 @@ function lostpass_content(&$a) {
$salt = random_string(32);
$password_encoded = hash('whirlpool', $salt . $new_password);
$r = q("UPDATE account SET account_salt = '%s', account_password = '%s', account_reset = '' where account_id = %d",
$r = q("UPDATE account SET account_salt = '%s', account_password = '%s', account_reset = '', account_flags = (account_flags & ~%d) where account_id = %d",
dbesc($salt),
dbesc($password_encoded),
intval(ACCOUNT_UNVERIFIED),
intval($aid)
);

View File

@ -68,6 +68,10 @@ function setup_post(&$a) {
$adminmail = trim($_POST['adminmail']);
$siteurl = trim($_POST['siteurl']);
// $siteurl should not have a trailing slash
$siteurl = rtrim($siteurl,'/');
require_once('include/dba/dba_driver.php');
unset($db);
$db = dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, true);

View File

@ -13,11 +13,15 @@ function uexport_init(&$a) {
$year = intval(argv(1));
}
if(argc() > 2 && intval(argv(2)) > 0 && intval(argv(2)) <= 12) {
$month = intval(argv(2));
}
header('content-type: application/octet_stream');
header('content-disposition: attachment; filename="' . $channel['channel_address'] . (($year) ? '-' . $year : '') . '.json"' );
header('content-disposition: attachment; filename="' . $channel['channel_address'] . (($year) ? '-' . $year : '') . (($month) ? '-' . $month : '') . '.json"' );
if($year) {
echo json_encode(identity_export_year(local_channel(),$year));
echo json_encode(identity_export_year(local_channel(),$year,$month));
killme();
}

View File

@ -1 +1 @@
2015-08-05.1115
2015-08-18.1128

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -61,7 +61,12 @@
#adminpage table tr:hover { background-color: #bbc7d7; }
#adminpage .selectall { text-align: right; }
.checkbox_bulkedit {
width: 1.2em;
height: 1.2em;
}
.channels_ckbx, .pending_ckbx, .users_ckbx {
margin-top: -5px !important;
margin-top: 0px !important;
margin-left: 0px !important;
}

View File

@ -1,70 +0,0 @@
<?php
// Set the following for your MySQL installation
// Copy or rename this file to .htconfig.php
$db_host = '{{$dbhost}}';
$db_port = '{{$dbport}}';
$db_user = '{{$dbuser}}';
$db_pass = '{{$dbpass}}';
$db_data = '{{$dbdata}}';
/*
* Notice: Many of the following settings will be available in the admin panel
* after a successful site install. Once they are set in the admin panel, they
* are stored in the DB - and the DB setting will over-ride any corresponding
* setting in this file
*
* The command-line tool util/config is able to query and set the DB items
* directly if for some reason the admin panel is not available and a system
* setting requires modification.
*
*/
// Choose a legal default timezone. If you are unsure, use "America/Los_Angeles".
// It can be changed later and only applies to timestamps for anonymous viewers.
$default_timezone = '{{$timezone}}';
// What is your site name?
$a->config['system']['baseurl'] = '{{$siteurl}}';
$a->config['system']['sitename'] = "Hubzilla";
$a->config['system']['location_hash'] = '{{$site_id}}';
// Your choices are REGISTER_OPEN, REGISTER_APPROVE, or REGISTER_CLOSED.
// Be certain to create your own personal account before setting
// REGISTER_CLOSED. 'register_text' (if set) will be displayed prominently on
// the registration page. REGISTER_APPROVE requires you set 'admin_email'
// to the email address of an already registered person who can authorise
// and/or approve/deny the request.
$a->config['system']['register_policy'] = REGISTER_OPEN;
$a->config['system']['register_text'] = '';
$a->config['system']['admin_email'] = '{{$adminmail}}';
// Maximum size of an imported message, 0 is unlimited
$a->config['system']['max_import_size'] = 200000;
// maximum size of uploaded photos
$a->config['system']['maximagesize'] = 8000000;
// Location of PHP command line processor
$a->config['system']['php_path'] = '{{$phpath}}';
// Configure how we communicate with directory servers.
// DIRECTORY_MODE_NORMAL = directory client, we will find a directory
// DIRECTORY_MODE_SECONDARY = caching directory or mirror
// DIRECTORY_MODE_PRIMARY = main directory server
// DIRECTORY_MODE_STANDALONE = "off the grid" or private directory services
$a->config['system']['directory_mode'] = DIRECTORY_MODE_NORMAL;
// default system theme
$a->config['system']['theme'] = 'redbasic';

View File

@ -1,32 +1,32 @@
Dear {{$username}},
A request was recently received at {{$sitename}} to reset your account
password. In order to confirm this request, please select the verification link
below or paste it into your web browser address bar.
Estimado {{$username}},
Una petición fue recibida recientemente en {{$sitename}} para cambiar la contraseña de su cuenta
contraseña. Para confirmar esta petición, por favor, selecciona el enlace de verificación
de más abajo o corte y pégelo en la barra de su navegador web.
If you did NOT request this change, please DO NOT follow the link
provided and ignore and/or delete this email.
Si no hizo esta petición de cambio, por favor, NO siga el enlace
que encontrará más abajo e ignore y/o borre este correo electrónico.
Your password will not be changed unless we can verify that you
issued this request.
Su contraseña no será cambiada hasta que verifiquemos que es usted
envió esta petición.
Follow this link to verify your identity:
Siga el enlace para verificar su identidad:
{{$reset_link}}
You will then receive a follow-up message containing the new password.
Seguidamente recibirá un mensaje con la nueva contraseña.
You may change that password from your account settings page after logging in.
Puede cambiar esta contraseña desde tu cuenta después de iniciar sesión.
The login details are as follows:
Los detalles del inicio de sesión son los siguientes:
Site Location: {{$siteurl}}
Login Name: {{$email}}
Localización del Sitio: {{$siteurl}}
Nombre de usuario: {{$email}}
Sincerely,
{{$sitename}} Administrator
Atentamente,
Administrador de {{$sitename}}

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,20 @@
Dear {{$username}},
Your password has been changed as requested. Please retain this
information for your records (or change your password immediately to
something that you will remember).
Estimado {{$username}},
Su contraseña ha sido cambiada, tal como pidió. Por favor, guarde esta
información en sus registros ( o cambie la contraseña inmediatamente
a alguna que pueda recordar).
Your login details are as follows:
Los detalles del inicio de sesión son los siguientes:
Site Location: {{$siteurl}}
Login Name: {{$email}}
Password: {{$new_password}}
Localización del Sitio: {{$siteurl}}
Nombre de usuario: {{$email}}
Contraseña: {{$new_password}}
You may change that password from your account settings page after logging in.
Puede cambiar esta contraseña desde su cuenta después de iniciar sesión.
Sincerely,
{{$sitename}} Administrator
Atentamente,
Administrador de {{$sitename}}

View File

@ -1,19 +1,19 @@
An account has been created at {{$sitename}} for this email address.
The login details are as follows:
Una cuenta ha sido creada en {{$sitename}} con esta dirección de correo electrónico.
Los detalles del inicio de sesión son los siguientes:
Site Location: {{$siteurl}}
Login: {{$email}}
Password: (the password which was provided during registration)
Localización del Sitio: {{$siteurl}}
Nombre de usuario: {{$email}}
Contraseña: (la contraseña que proporcionó durante el proceso de registro)
If this account was created without your knowledge and is not desired, you may
visit this site and reset the password. This will allow you to remove the
account from the links on the Settings page, and we
apologise for any inconvenience.
Si esta cuenta se creó sin su consentimiento y no es deseada, puedes
visitar el sitio y cambiar la contraseña. Esto le permitirá eliminar la
cuenta de los enlaces en la página de Ajustes, le
pedimos disculpas por cualquier inconveniente que hayamos podido causar.
Thank you and welcome to {{$sitename}}.
gracias y bienvenido a {{$sitename}}.
Sincerely,
{{$sitename}} Administrator
Atentamente,
Administrador de {{$sitename}}

View File

@ -1,25 +1,24 @@
A new user registration request was received at {{$sitename}} which requires
your approval.
Una nueva petición de registro de usuario se ha recibido en {{$sitename}}, que requiere
su aprobación.
The login details are as follows:
Los detalles del inicio de sesión son los siguientes:
Site Location: {{$siteurl}}
Login Name: {{$email}}
IP Address: {{$details}}
Localización del Sitio: {{$siteurl}}
Nombre de usuario: {{$email}}
Dirección IP: {{$details}}
To approve this request please visit the following link:
Para aprobar la petición siga el enlace:
{{$siteurl}}/regmod/allow/{{$hash}}
To deny the request and remove the account, please visit:
Para denegar la petición y eliminar la cuenta , siga:
{{$siteurl}}/regmod/deny/{{$hash}}
Thank you.
Gracias.

View File

@ -0,0 +1,24 @@
Gracias por registrarse en {{$sitename}}.
Los detalles del inicio de sesión son los siguientes:
Localización del Sitio: {{$siteurl}}
Nombre de usuario: {{$email}}
inicie la sesión con la contraseña que elegió durante el registro.
Necesitamos verificar su correo electrónico para poder darle pleno acceso.
Si registró esta cuenta, por favor, siga el enlace:
{{$siteurl}}/regver/allow/{{$hash}}
Para denegar la petición y eliminar la cuenta , siga:
{{$siteurl}}/regver/deny/{{$hash}}
Gracias.

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,14 @@
Hey,
I'm the web server at {{$sitename}};
Soy el servidor web en {{$sitename}};
The Hubzilla developers released update {{$update}} recently,
but when I tried to install it, something went terribly wrong.
This needs to be fixed soon and it requires human intervention.
Please contact a Red developer if you can not figure out how to
fix it on your own. My database might be invalid.
Los desarrolladores de RedMatrix/Hubzilla han lanzado la actualización {{$update}} recientemente,
pero cuando se intentaba instalar, alguna cosa ha ido terriblemente mal.
Esto requiere intervención humana tan pronto como sea posible.
Por favor, contacte con algún desarrollador de Red si no puede arreglarlo
por sí mismo. Mi base se datos puede quedar inservible.
The error message is '{{$error}}'.
Apologies for the inconvenience,
your web server at {{$siteurl}}
El mensaje de error ha sido el siguiente: '{{$error}}'.
Disculpe por cualquier inconveniente causado,
su servidor web en {{$siteurl}}

View File

@ -2,6 +2,7 @@
[region=aside]
[widget=collections][/widget]
[widget=forums][/widget]
[widget=suggestions][/widget]
[widget=savedsearch][/widget]
[widget=filer][/widget]

View File

@ -2293,6 +2293,6 @@ nav .badge.mail-update:hover {
background-color: #337AB7;
}
.channels_ckbx, .pending_ckbx, .users_ckbx {
/*.channels_ckbx, .pending_ckbx, .users_ckbx {
margin-top: -5px !important;
}
}*/

View File

@ -32,7 +32,7 @@
<td class='channel_id'>{{$c.channel_id}}</td>
<td class='channel_name'><a href="channel/{{$c.channel_address}}">{{$c.channel_name}}</a></td>
<td class='channel_address'>{{$c.channel_address}}</td>
<td class="checkbox"><input type="checkbox" class="channels_ckbx" id="id_channel_{{$c.channel_id}}" name="channel[]" value="{{$c.channel_id}}"/></td>
<td class="checkbox_bulkedit"><input type="checkbox" class="channels_ckbx" id="id_channel_{{$c.channel_id}}" name="channel[]" value="{{$c.channel_id}}"/></td>
<td class="tools">
<a href="{{$baseurl}}/admin/channels/block/{{$c.channel_id}}?t={{$form_security_token}}" class="btn btn-default btn-xs" title='{{if ($c.blocked)}}{{$unblock}}{{else}}{{$block}}{{/if}}'><i class='icon-ban-circle admin-icons {{if ($c.blocked)}}dim{{/if}}'></i></a>
<a href="{{$baseurl}}/admin/channels/code/{{$c.channel_id}}?t={{$form_security_token}}" class="btn btn-default btn-xs" title='{{if ($c.allowcode)}}{{$uncode}}{{else}}{{$code}}{{/if}}'><i class='icon-terminal admin-icons {{if ($c.allowcode)}}dim{{/if}}'></i></a>

View File

@ -31,7 +31,7 @@
<tr>
<td class="created">{{$u.account_created}}</td>
<td class="email">{{$u.account_email}}</td>
<td class="checkbox"><input type="checkbox" class="pending_ckbx" id="id_pending_{{$u.hash}}" name="pending[]" value="{{$u.hash}}"></td>
<td class="checkbox_bulkedit"><input type="checkbox" class="pending_ckbx" id="id_pending_{{$u.hash}}" name="pending[]" value="{{$u.hash}}"></td>
<td class="tools">
<a href="{{$baseurl}}/regmod/allow/{{$u.hash}}" class="btn btn-default btn-xs" title="{{$approve}}"><i class="icon-thumbs-up-alt admin-icons"></i></a>
<a href="{{$baseurl}}/regmod/deny/{{$u.hash}}" class="btn btn-default btn-xs" title="{{$deny}}"><i class="icon-thumbs-down-alt admin-icons"></i></a>
@ -71,7 +71,7 @@
<td class="login_date">{{$u.account_lastlog}}</td>
<td class="account_expires">{{$u.account_expires}}</td>
<td class="service_class">{{$u.account_service_class}}</td>
<td class="checkbox"><input type="checkbox" class="users_ckbx" id="id_user_{{$u.account_id}}" name="user[]" value="{{$u.account_id}}"><input type="hidden" name="blocked[]" value="{{$u.blocked}}"></td>
<td class="checkbox_bulkedit"><input type="checkbox" class="users_ckbx" id="id_user_{{$u.account_id}}" name="user[]" value="{{$u.account_id}}"><input type="hidden" name="blocked[]" value="{{$u.blocked}}"></td>
<td class="tools">
<a href="{{$baseurl}}/admin/users/{{if ($u.blocked)}}un{{/if}}block/{{$u.account_id}}?t={{$form_security_token}}" class="btn btn-default btn-xs" title='{{if ($u.blocked)}}{{$unblock}}{{else}}{{$block}}{{/if}}'><i class="icon-ban-circle admin-icons{{if ($u.blocked)}} dim{{/if}}"></i></a><a href="{{$baseurl}}/admin/users/delete/{{$u.account_id}}?t={{$form_security_token}}" class="btn btn-default btn-xs" title='{{$delete}}' onclick="return confirm_delete('{{$u.name}}')"><i class="icon-trash admin-icons"></i></a>
</td>

15
view/tpl/item_import.tpl Executable file
View File

@ -0,0 +1,15 @@
<h2>{{$title}}</h2>
<form action="import_items" method="post" enctype="multipart/form-data" id="import-channel-form">
<div id="import-desc" class="descriptive-paragraph">{{$desc}}</div>
<label for="import-filename" id="label-import-filename" class="import-label" >{{$label_filename}}</label>
<input type="file" name="filename" id="import-filename" class="import-input" value="" />
<div id="import-filename-end" class="import-field-end"></div>
<input type="submit" name="submit" id="import-submit-button" value="{{$submit}}" />
<div id="import-submit-end" class="import-field-end"></div>
</form>