summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.xml168
-rw-r--r--data/schema/6.sql4
-rw-r--r--data/tables.sql7
-rw-r--r--data/templates/default/about.tpl.php2
-rw-r--r--data/templates/default/bookmarks.tpl.php14
-rw-r--r--data/templates/default/dojo.inc.php35
-rw-r--r--data/templates/default/editprofile.tpl.php8
-rw-r--r--data/templates/default/rss.tpl.php4
-rw-r--r--data/templates/default/top.inc.php4
-rw-r--r--data/templates/testdummy/top.inc.php2
-rw-r--r--doc/ChangeLog25
-rw-r--r--doc/INSTALL.txt8
-rw-r--r--doc/README.rst4
-rw-r--r--doc/UPGRADE.txt4
-rw-r--r--doc/allinone.rst31
-rw-r--r--doc/configuration.rst58
-rw-r--r--doc/developers/release-new-version.rst12
-rw-r--r--doc/index.rst5
-rw-r--r--res/docs/header.tpl.html8
-rw-r--r--res/docs/style.css25
-rw-r--r--src/SemanticScuttle/Config.php109
-rw-r--r--src/SemanticScuttle/Environment.php52
-rw-r--r--src/SemanticScuttle/Model/Bookmark.php17
-rw-r--r--src/SemanticScuttle/Model/User.php26
-rw-r--r--src/SemanticScuttle/Service/Bookmark.php1
-rw-r--r--src/SemanticScuttle/Service/Bookmark2Tag.php4
-rw-r--r--src/SemanticScuttle/Service/Tag.php4
-rw-r--r--src/SemanticScuttle/Service/User.php219
-rw-r--r--src/SemanticScuttle/constants.php14
-rw-r--r--src/SemanticScuttle/header.php18
-rw-r--r--tests/AllTests.php3
-rw-r--r--tests/Api/PostsAddTest.php4
-rw-r--r--tests/Bookmark2TagTest.php10
-rw-r--r--tests/BookmarkTest.php46
-rw-r--r--tests/SemanticScuttle/ConfigTest.php206
-rw-r--r--tests/SemanticScuttle/EnvironmentTest.php95
-rw-r--r--tests/Tag2TagTest.php1
-rw-r--r--tests/TestBase.php34
-rw-r--r--tests/TestBaseApi.php31
-rw-r--r--tests/UserTest.php333
-rwxr-xr-xtests/www/bookmarksTest.php92
-rw-r--r--tests/www/indexTest.php58
-rw-r--r--tests/www/rssTest.php151
-rw-r--r--tests/www/searchTest.php4
-rw-r--r--www/ajaxGetNewPrivateKey.php35
-rw-r--r--www/bookmarks.php27
-rw-r--r--www/index.php23
-rw-r--r--www/js/jstree-1.0-rc2/MultiComboBox.js72
-rw-r--r--www/jsScuttle.php18
-rw-r--r--www/profile.php33
-rw-r--r--www/rss.php34
-rw-r--r--www/tags.php24
52 files changed, 1901 insertions, 325 deletions
diff --git a/build.xml b/build.xml
index d0637c7..6bd5eb2 100644
--- a/build.xml
+++ b/build.xml
@@ -9,18 +9,31 @@
<property file="build.properties" />
<property file="html.properties" />
- <property name="version-m" value="0.97" />
- <property name="version" value="0.97.0" />
+ <property name="version-m" value="0.98" />
+ <property name="version" value="0.98.0" />
<property name="stability" value="beta" />
- <property name="releasenotes" value="- Many SQL optimizations
-- SemanticScuttle shows bookmarks 4 times faster now
-- New config option to skip 'SET NAMES UTF8' call: $dbneedssetnames
-- Do not highlight admin bookmarks when $enableAdminColors is disabled
-- Add russian translation
-- Make HTML export follow the specifications a bit better
-- Fix bug #2953732: faulty error message for duplicate bookmarks
-- Fix bug #2960663: do not send content-type headers twice for ajax/api scripts
-- Fix bug #2976593: fr_FR locale is vietnamese
+ <property name="releasenotes" value="- Switch to jQuery and drop dojo
+- Implement request #2928950: Private keys for RSS feeds (Mark Pemberton)
+- Implement request #3164348: Configurable default privacy (Brett Dee)
+- Implement request #1989987: Theming support
+- Implement request #3054906: Show user's full name instead of nickname
+- Implement patch #3059829: update ``FR_CA`` translation
+- Fix bug #3187177: Wrong URL / Export XML Bookmarks
+- Fix bug #3097187: Using opensearch with two tags does not work in Firefox
+- Fix bug #3251877: French translation JavaScript Bug when editing bookmarks
+- Fix bug #3168521: Title of tag-filtered RSS Feed is broken
+- Fix bug #2853627: Javascript warning
+- Fix bug in ``getTagsForBookmarks()`` that fetched all tags
+- Fix privacy issue when fetching tags of several users
+- Fix Google custom search XML
+- Show error message on mysqli connection errors
+- Update php-gettext library to 1.0.10
+- ``api/posts/add`` respects the 'replace' parameter now
+- Only URLs with an allowed protocol may be added to the database
+- Support HTTPS connections when ``$root`` is not configured
+- SQL schema version table to ease future database upgrades
+- Documentation is written with rST (reStructuredText) now
+- Support per-host configuration files
" />
<property name="zipfile" value="${phing.project.name}-${version}.zip" />
<property name="pkgfile" value="${phing.project.name}-${version}.tgz" />
@@ -30,7 +43,8 @@
<property name="sffilepath" value="s/se/semanticscuttle/" />
<property name="svnpath" value="https://semanticscuttle.svn.sourceforge.net/svnroot/semanticscuttle/" />
- <taskdef classname="phing.tasks.ext.d51PearPkg2Task" name="d51pearpkg2" />
+ <taskdef name="rST" classname="phing.tasks.ext.rSTTask" />
+ <taskdef name="d51pearpkg2" classname="phing.tasks.ext.d51PearPkg2Task" />
<target name="zip" depends="check"
description="Create zip file for release"
@@ -52,11 +66,12 @@
<exclude name="**/.gitignore/"/>
<exclude name="**/.svn/"/>
<exclude name="data/config.php"/>
+ <exclude name="data/config.testing.php"/>
+ <exclude name="data/config.testing-tmp.php"/>
<exclude name="data/locales/messages.po"/>
<exclude name="data/locales/*/LC_MESSAGES/messages.po"/>
- <exclude name="doc/developers/"/>
<exclude name="src/php-gettext/examples/" />
- <exclude name="src/php-gettext/bin/"/>
+ <exclude name="src/php-gettext/tests/"/>
</fileset>
</zip>
</target>
@@ -66,7 +81,6 @@
<target name="package" depends="check"
description="Creates the pear package"
>
- <!-- fixme: create package.xml with d51pearpkg2 -->
<d51pearpkg2 dir="." baseinstalldir="/">
<name>SemanticScuttle</name>
<summary>A social bookmarking tool</summary>
@@ -108,30 +122,34 @@
<ignore>**/.svn</ignore>
<ignore>build*</ignore>
<ignore>data/config.php</ignore>
+ <ignore>data/config.testing.php</ignore>
+ <ignore>data/config.testing-tmp.php</ignore>
<ignore>data/locales/messages.po</ignore>
<ignore>data/locales/*/LC_MESSAGES/messages.po</ignore>
<ignore>dist/**</ignore>
- <ignore>doc/developers/**</ignore>
<ignore>scripts/**</ignore>
<ignore>src/php-gettext/examples/**</ignore>
- <ignore>src/php-gettext/bin/**</ignore>
- <ignore>*.tgz</ignore>
+ <ignore>src/php-gettext/tests/**</ignore>
<ignore>*.properties</ignore>
+ <ignore>semanticscuttle-dump.sql</ignore>
+ <ignore>*.tgz</ignore>
- <replacement
- path="src/SemanticScuttle/header.php"
+ <replacement path="src/SemanticScuttle/header.php"
+ type="pear-config" from="@data_dir@" to="data_dir"
+ />
+ <replacement path="src/SemanticScuttle/header.php"
+ type="pear-config" from="@www_dir@" to="www_dir"
+ />
+ <replacement path="src/SemanticScuttle/Config.php"
type="pear-config" from="@data_dir@" to="data_dir"
/>
- <replacement
- path="src/SemanticScuttle/header.php"
+ <replacement path="src/SemanticScuttle/Config.php"
type="pear-config" from="@www_dir@" to="www_dir"
/>
- <replacement
- path="www/www-header.php"
+ <replacement path="www/www-header.php"
type="pear-config" from="@data_dir@" to="data_dir"
/>
- <replacement
- path="tests/prepare.php"
+ <replacement path="tests/prepare.php"
type="pear-config" from="@data_dir@" to="data_dir"
/>
@@ -207,49 +225,31 @@
</target>
- <!-- you need to have the python docutils package installed, since
- we use the rst2html tool -->
- <target name="build-docs">
- <foreach param="fname" absparam="abs-fname" target="build-doc-file">
- <fileset dir=".">
- <include name="doc/ChangeLog"/>
- <include name="doc/**.txt"/>
- <include name="doc/**.rst"/>
- <include name="doc/**/*.rst"/>
- <exclude name="doc/LICENSE.txt"/>
- <exclude name="doc/developers/TODO.rst"/>
- </fileset>
- </foreach>
- </target>
-
-
- <target name="build-doc-file" depends="check"
- description="Builds a single documentation file. Pass file path as $fname"
- >
- <echo msg="${fname}"/>
- <php function="preg_replace" returnProperty="outfile">
- <param value="/^(.+)(.rst|.txt)$/"/>
- <param value="dist/\1.html"/>
- <param value="${fname}"/>
- </php>
-
- <!-- only render file if the doc file is newer than the html file -->
- <property name="isuptodate" value="false"/>
- <uptodate property="isuptodate" srcfile="${fname}" targetfile="${outfile}" />
- <if>
- <not><istrue value="${isuptodate}"/></not>
- <then>
- <exec
- command="rst2html --exit-status=2 ${fname} ${outfile}"
- checkreturn="1"
- />
- </then>
- </if>
-
+ <target name="build-docs" description="render documentation">
+ <rST format="html" uptodate="true"
+ toolparam="--stylesheet=res/docs/style.css"
+ >
+ <fileset dir="doc">
+ <include name="ChangeLog"/>
+ <include name="**.txt"/>
+ <include name="**.rst"/>
+ <include name="**/*.rst"/>
+ <exclude name="LICENSE.txt"/>
+ <exclude name="developers/TODO.rst"/>
+ <exclude name="allinone.rst"/>
+ </fileset>
+ <mapper type="regexp" from="^doc/(.+?)(.rst|.txt)?$" to="dist/docs/\1.html"/>
+<!--
+ <filterchain>
+ <replacetokenswithfile dir="res/docs">
+ <
+ </replacetokenswithfile>
+ </filterchain>
+-->
+ </rST>
</target>
-
<target name="release" depends="check,zip,package,deploy-sf"
description="Release the version on sourceforge"
>
@@ -284,7 +284,7 @@
<target name="deploy-sf-pear" depends="check,package"
- description="Update PEAR channel on sourceforge"
+ description="Update PEAR channel + website on sourceforge"
>
<available file="${websitedir}"
type="dir" property="available.websitedir"
@@ -349,6 +349,38 @@
</target>
+ <target name="deploy-docs" depends="build-docs"
+ description="sync docs to sourceforge website"
+ >
+ <copy todir="${websitedir}/docs">
+ <fileset dir="dist/docs">
+ <include name="**"/>
+ </fileset>
+ </copy>
+
+ <exec
+ command="rsync -avP -e ssh . ${sfuser},${sfproject}@web.sourceforge.net:htdocs/docs"
+ dir="${websitedir}/docs"
+ escape="false" checkreturn="false"
+ passthru="true"
+ />
+ </target>
+
+
+ <target name="deploy-demo"
+ description="sync demo to sourceforge website"
+ >
+ <exec
+ command="rsync -avP -e ssh . ${sfuser},${sfproject}@web.sourceforge.net:htdocs/demo"
+ dir="${websitedir}/demo"
+ escape="false" checkreturn="false"
+ passthru="true"
+ />
+ </target>
+
+
+
+
<target name="check"
description="Check variables"
>
@@ -358,8 +390,6 @@
<fail unless="sffilepath" message="Sourceforge project file path not defined!" />
<mkdir dir="dist" />
- <mkdir dir="dist/doc" />
- <mkdir dir="dist/doc/developers" />
</target>
</project>
diff --git a/data/schema/6.sql b/data/schema/6.sql
index 0c208ad..cf9dd37 100644
--- a/data/schema/6.sql
+++ b/data/schema/6.sql
@@ -13,3 +13,7 @@ CREATE TABLE `sc_users_sslclientcerts` (
PRIMARY KEY ( `id` ) ,
UNIQUE (`id`)
) CHARACTER SET utf8 COLLATE utf8_general_ci;
+
+ALTER TABLE `sc_users` ADD `privateKey` VARCHAR(33) NULL;
+CREATE UNIQUE INDEX `privateKey` ON `sc_users` (`privateKey`);
+
diff --git a/data/tables.sql b/data/tables.sql
index d53945e..68d5ba9 100644
--- a/data/tables.sql
+++ b/data/tables.sql
@@ -72,7 +72,9 @@ CREATE TABLE `sc_users` (
`email` varchar(50) NOT NULL default '',
`homepage` varchar(255) default NULL,
`uContent` text,
- PRIMARY KEY (`uId`)
+ `privateKey` varchar(33) default NULL,
+ PRIMARY KEY (`uId`),
+ UNIQUE KEY `privateKey` (`privateKey`)
) CHARACTER SET utf8 COLLATE utf8_general_ci ;
-- --------------------------------------------------------
@@ -84,8 +86,7 @@ CREATE TABLE `sc_users_sslclientcerts` (
`sslClientIssuerDn` VARCHAR( 1024 ) NOT NULL ,
`sslName` VARCHAR( 64 ) NOT NULL ,
`sslEmail` VARCHAR( 64 ) NOT NULL ,
- PRIMARY KEY ( `id` ) ,
- UNIQUE (`id`)
+ PRIMARY KEY ( `id` )
) CHARACTER SET utf8 COLLATE utf8_general_ci;
--
diff --git a/data/templates/default/about.tpl.php b/data/templates/default/about.tpl.php
index 7bff98d..8a9b206 100644
--- a/data/templates/default/about.tpl.php
+++ b/data/templates/default/about.tpl.php
@@ -17,7 +17,7 @@ $this->includeTemplate($GLOBALS['top_include']);
<?php if(!is_null($currentUser) && $currentUser->isAdmin()): ?>
-<li>SemanticScuttle v0.97.0</li>
+<li>SemanticScuttle v0.98.0</li>
<?php endif ?>
</ul>
diff --git a/data/templates/default/bookmarks.tpl.php b/data/templates/default/bookmarks.tpl.php
index 91d50bf..0ed9c1d 100644
--- a/data/templates/default/bookmarks.tpl.php
+++ b/data/templates/default/bookmarks.tpl.php
@@ -221,13 +221,13 @@ if ($currenttag!= '') {
$brss = '';
$size = count($rsschannels);
for ($i = 0; $i < $size; $i++) {
- $brss = '<a style="background:#FFFFFF"'
- . ' href="'. htmlspecialchars($rsschannels[$i][1]) . '"'
- . ' title="' . htmlspecialchars($rsschannels[$i][0]) . '">'
- . '<img src="' . $theme->resource('images/rss.gif') . '"'
- . ' width="16" height="16"'
- . ' alt="' . htmlspecialchars($rsschannels[$i][0]) .'"/>'
- . '</a>';
+ $brss = '<a style="background:#FFFFFF"'
+ . ' href="'. htmlspecialchars($rsschannels[$i][1]) . '"'
+ . ' title="' . htmlspecialchars($rsschannels[$i][0]) . '">'
+ . '<img src="' . $theme->resource('images/rss.gif') . '"'
+ . ' width="16" height="16"'
+ . ' alt="' . htmlspecialchars($rsschannels[$i][0]) .'"/>'
+ . '</a>';
}
$pagesBanner = '<p class="paging">'. $bfirst .'<span> / </span>'. $bprev .'<span> / </span>'. $bnext .'<span> / </span>'. $blast .'<span> / </span>'. sprintf(T_('Page %d of %d'), $page, $totalpages) ." ". $brss ." </p>\n";
diff --git a/data/templates/default/dojo.inc.php b/data/templates/default/dojo.inc.php
deleted file mode 100644
index 366dcfe..0000000
--- a/data/templates/default/dojo.inc.php
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-/***************************************************************************
- Copyright (C) 2005 - 2006 Scuttle project
- http://sourceforge.net/projects/scuttle/
- http://scuttle.org/
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- ***************************************************************************/
-
-?>
-
-<?php if (isset($loadjs)) :?>
-<script type="text/javascript"
- src="http://ajax.googleapis.com/ajax/libs/dojo/1.2/dojo/dojo.xd.js"
- djConfig="parseOnLoad:true, isDebug:<?php echo DEBUG_MODE?'true':'false' ?>, usePlainJson:true, baseUrl: '<?php echo ROOT ?>', modulePaths: {'js': 'js'}"></script>
-
-<script type="text/javascript">
-dojo.require("dojo.parser");
-dojo.require("dojo.data.ItemFileReadStore");
-dojo.require("js.MultiComboBox"); // DOJO module adapted for SemanticScuttle
-dojo.require("dijit.Tree");
-</script>
-<?php endif ?> \ No newline at end of file
diff --git a/data/templates/default/editprofile.tpl.php b/data/templates/default/editprofile.tpl.php
index cc74f04..25dc3a4 100644
--- a/data/templates/default/editprofile.tpl.php
+++ b/data/templates/default/editprofile.tpl.php
@@ -28,6 +28,14 @@ $this->includeTemplate($GLOBALS['top_include']);
<td><input type="text" name="pMail" size="75" value="<?php echo filter($objectUser->getEmail(), 'xml'); ?>" /></td>
<td>← <?php echo T_('Required'); ?></td>
</tr>
+<tr>
+ <th align="left"><?php echo T_('Private RSS Feed'); ?></th>
+ <td><input type="checkbox" id="pEnablePrivateKey" name="pEnablePrivateKey" value="true" <?php echo $privateKeyIsEnabled;?> />
+ <label for="pEnablePrivateKey"><?php echo T_('Enable'); ?></label>&nbsp;&nbsp;&nbsp;
+ <input type="text" id="pPrivateKey" name="pPrivateKey" size="40" value="<?php echo $privateKey;?>" readonly="readonly" />
+ <a onclick="getNewPrivateKey(this); return false;"><button type="submit" name="submittedPK" value="1"><?php echo T_('Generate New Key'); ?></button></a>
+ </td>
+</tr>
</table>
<h3><?php echo T_('Personal Details'); ?></h3>
diff --git a/data/templates/default/rss.tpl.php b/data/templates/default/rss.tpl.php
index e6e66f7..6be5425 100644
--- a/data/templates/default/rss.tpl.php
+++ b/data/templates/default/rss.tpl.php
@@ -3,7 +3,7 @@ echo '<' . '?xml version="1.0" encoding="utf-8" ?' . ">\n";
?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
- <title><?php echo htmlspecialchars($feedtitle); ?></title>
+ <title><?php echo $feedtitle; ?></title>
<link><?php echo htmlspecialchars($feedlink); ?></link>
<description><?php echo htmlspecialchars($feeddescription); ?></description>
<pubDate><?php echo date('r'); ?></pubDate>
@@ -23,4 +23,4 @@ echo '<' . '?xml version="1.0" encoding="utf-8" ?' . ">\n";
</item>
<?php endforeach; ?>
</channel>
-</rss> \ No newline at end of file
+</rss>
diff --git a/data/templates/default/top.inc.php b/data/templates/default/top.inc.php
index 9eed6ff..17ec982 100644
--- a/data/templates/default/top.inc.php
+++ b/data/templates/default/top.inc.php
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?php echo '<'; ?>?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
@@ -13,7 +13,7 @@ if (isset($rsschannels)) {
for ($i = 0; $i < $size; $i++) {
echo ' <link rel="alternate" type="application/rss+xml" title="'
. htmlspecialchars($rsschannels[$i][0]) . '"'
- . ' href="'. $rsschannels[$i][1] .'" />';
+ . ' href="'. htmlspecialchars($rsschannels[$i][1]) .'" />' . "\n";
}
}
?>
diff --git a/data/templates/testdummy/top.inc.php b/data/templates/testdummy/top.inc.php
index 7b0874c..b85a1ae 100644
--- a/data/templates/testdummy/top.inc.php
+++ b/data/templates/testdummy/top.inc.php
@@ -12,7 +12,7 @@ if (isset($rsschannels)) {
$size = count($rsschannels);
for ($i = 0; $i < $size; $i++) {
echo ' <link rel="alternate" type="application/rss+xml" title="'
- . htmlspecialchars($rsschannels[$i][0]) . '"'
+ . $rsschannels[$i][0] . '"'
. ' href="'. $rsschannels[$i][1] .'" />';
}
}
diff --git a/doc/ChangeLog b/doc/ChangeLog
index cde9e61..f963ca2 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,28 +1,39 @@
ChangeLog for SemantiScuttle
============================
+.. contents::
-0.98.0 - 2011-XX-XX
+0.98.1 - 2011-XX-XX
+-------------------
+- Fix bug #3375635: XML parsing problem in top.inc.php
+- Fix bug #3375428: Forgot to remove some old dojo files
+- Fix bug #3160512: Make SemanticScuttle work with FastCGI
+
+
+0.98.0 - 2011-07-21
-------------------
- Switch to jQuery and drop dojo
+- Implement request #2928950: Private keys for RSS feeds (Mark Pemberton)
+- Implement request #3164348: Configurable default privacy (Brett Dee)
+- Implement request #1989987: Theming support
+- Implement request #3054906: Show user's full name instead of nickname
+- Implement patch #3059829: update ``FR_CA`` translation
- Fix bug #3187177: Wrong URL / Export XML Bookmarks
-- Fix bug in ``getTagsForBookmarks()`` that fetched all tags
- Fix bug #3097187: Using opensearch with two tags does not work in Firefox
- Fix bug #3251877: French translation JavaScript Bug when editing bookmarks
- Fix bug #3168521: Title of tag-filtered RSS Feed is broken
- Fix bug #2853627: Javascript warning
-- Implement request #1989987: Theming support
-- Implement request #3054906: Show user's full name instead of nickname
-- Implement patch #3059829: update ``FR_CA`` translation
+- Fix bug in ``getTagsForBookmarks()`` that fetched all tags
+- Fix privacy issue when fetching tags of several users
+- Fix Google custom search XML
- Show error message on mysqli connection errors
- Update php-gettext library to 1.0.10
- ``api/posts/add`` respects the "replace" parameter now
-- Fix privacy issue when fetching tags of several users
-- Fix Google custom search XML
- Only URLs with an allowed protocol may be added to the database
- Support HTTPS connections when ``$root`` is not configured
- SQL schema version table to ease future database upgrades
- Documentation is written with rST (reStructuredText) now
+- Support per-host configuration files
0.97.2 - 2011-02-17
diff --git a/doc/INSTALL.txt b/doc/INSTALL.txt
index 5afc732..fbd44f9 100644
--- a/doc/INSTALL.txt
+++ b/doc/INSTALL.txt
@@ -22,7 +22,7 @@ Installation instructions
on the shell ("semanticscuttle" being the database name)
3. Copy ``data/config.php.dist`` to ``data/config.php`` and modify it as
- necessary.
+ necessary. See configuration_ for more information.
4. Make the cache directory writable by your web server.
For example, run ::
@@ -31,6 +31,12 @@ Installation instructions
on the shell.
5. Set the ``www/`` directory as document root in your web server,
restart the web server.
+6. That's all! Visit your SemanticScuttle installation web site now
+ with your browser.
+7. Register a user and add bookmarks.
+
+
+.. _configuration: configuration.html
Ugly www directory in URLs
diff --git a/doc/README.rst b/doc/README.rst
index 0c7befe..7702400 100644
--- a/doc/README.rst
+++ b/doc/README.rst
@@ -4,7 +4,9 @@ SemanticScuttle 0.98
A social bookmarking tool experimenting with new features
like structured tags or collaborative descriptions of tags.
-https://sourceforge.net/projects/semanticscuttle/
+- Home page: http://semanticscuttle.sourceforge.net/
+- Project page: https://sourceforge.net/projects/semanticscuttle/
+- Demo: http://semanticscuttle.sourceforge.net/demo/
Available under the GNU General Public License
diff --git a/doc/UPGRADE.txt b/doc/UPGRADE.txt
index 0e570e5..b144af2 100644
--- a/doc/UPGRADE.txt
+++ b/doc/UPGRADE.txt
@@ -2,6 +2,7 @@
Upgrading SemanticScuttle from a previous version
=================================================
+.. contents::
From version 0.97 to 0.98
=========================
@@ -9,6 +10,9 @@ Database updates
----------------
Apply ``data/schema/6.sql``
+ ALTER TABLE `sc_users` ADD `privateKey` VARCHAR(33) NULL;
+ CREATE UNIQUE INDEX `privateKey` ON `sc_users` (`privateKey`);
+
From version 0.96 to 0.97
=========================
diff --git a/doc/allinone.rst b/doc/allinone.rst
new file mode 100644
index 0000000..e5ca3c7
--- /dev/null
+++ b/doc/allinone.rst
@@ -0,0 +1,31 @@
+=============================
+SemanticScuttle documentation
+=============================
+
+.. contents::
+
+First reads
+===========
+.. include:: README.rst
+.. include:: INSTALL.txt
+.. include:: UPGRADE.txt
+
+
+
+Features
+========
+.. include:: authentication.rst
+.. include:: ssl-client-certificates.rst
+.. include:: themes.rst
+
+
+
+Developer documentation
+=======================
+.. include:: developers/rules.rst
+.. include:: developers/api.rst
+.. include:: developers/debugging.rst
+.. include:: developers/release-new-version.rst
+.. include:: developers/running-unit-tests.rst
+.. include:: developers/translation.rst
+.. include:: ChangeLog
diff --git a/doc/configuration.rst b/doc/configuration.rst
new file mode 100644
index 0000000..f457ebb
--- /dev/null
+++ b/doc/configuration.rst
@@ -0,0 +1,58 @@
+===================
+Configuration files
+===================
+
+SemanticScuttle uses at least two configuration files:
+
+1. Default configuration file ``config.default.php``
+2. Custom configuration file ``config.php``
+
+
+The **default configuration** file contains sensible defaults for most users
+that do not need to be changed to get started.
+
+Never change it - it will get overwritten with the next update.
+If you want to change values in it, copy them into your personal
+``config.php`` file - updates to SemanticScuttle will not change that one.
+
+The **custom configuration** file, ``config.php`` is created by copying the
+shipped ``config.php.dist`` file and modifying the values in there.
+
+It consists of the configuration directives that should be set on every
+fresh installation.
+
+
+
+Configuration scenarios
+=======================
+
+Simple installation
+-------------------
+Put your configuration file in ``data/config.php``.
+If you installed SemanticScuttle's PEAR package, use::
+
+ $ pear config-get data_dir
+ /usr/share/php/data
+
+to find the data directory location and append ``SemanticScuttle/`` to it.
+In this case, the configuration file has to be in::
+
+ /usr/share/php/data/SemanticScuttle/config.php
+
+
+The configuration file may also be saved into::
+
+ /etc/semanticscuttle/config.php
+
+
+Multiple SemanticScuttle instances
+----------------------------------
+The files of one single SemanticScuttle installation may be shared
+for several SemanticScuttle instances.
+
+To be able to configure them differently, SemanticScuttle supports
+per-host configuration files:
+
+- ``data/config.$hostname.php``
+- ``/etc/semanticscuttle/config.$hostname.php``
+
diff --git a/doc/developers/release-new-version.rst b/doc/developers/release-new-version.rst
index 4b2540a..a5e77dc 100644
--- a/doc/developers/release-new-version.rst
+++ b/doc/developers/release-new-version.rst
@@ -2,18 +2,18 @@ How to release a new version of SemanticScuttle
===============================================
0. Run unit tests and verify that all of them pass
-1. Update doc/ChangeLog
-2. Update doc/UPGRADE.txt
-3. Update version in data/templates/about.tpl.php,
- build.xml and doc/README.txt
+1. Update ``doc/ChangeLog``
+2. Update ``doc/UPGRADE.txt``
+3. Update version in ``data/templates/about.tpl.php``,
+ ``build.xml`` and ``doc/README.rst``
4. Create a release zip file via the build script:
- Just type "phing".
+ Just type "``phing``".
5. Make a test installation from your zip file with a fresh
database. Register a user, add bookmarks etc.
6. When all is fine, it's time to release.
The build script takes care for most of the
tasks.
- Run "phing release", and it will upload the release to
+ Run "``phing release``", and it will upload the release to
sourceforge and create a svn tag.
7. Write announcement mail to the SemanticScuttle mailing list
semanticscuttle-devel@lists.sourceforge.net
diff --git a/doc/index.rst b/doc/index.rst
index 1b8feea..0a53680 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -20,10 +20,12 @@ Features
- `Custom user authentication`__
- `SSL Client certificates`__
- Themes__
+- `Configuration files`__
__ authentication.html
__ ssl-client-certificates.html
__ themes.html
+__ configuration.html
@@ -35,6 +37,7 @@ Developer documentation
- `How to release a new version`__
- `Running unit testes`__
- `How to translate SemanticScuttle`__
+- `ChangeLog`__
__ developers/rules.html
__ developers/api.html
@@ -42,4 +45,4 @@ __ developers/debugging.html
__ developers/release-new-version.html
__ developers/running-unit-tests.html
__ developers/translation.html
-
+__ ChangeLog.html
diff --git a/res/docs/header.tpl.html b/res/docs/header.tpl.html
new file mode 100644
index 0000000..ee0650f
--- /dev/null
+++ b/res/docs/header.tpl.html
@@ -0,0 +1,8 @@
+<ul class="menu">
+ <li><a href="index.html">Index</a></li>
+ <li><a href="INSTALL.html">Installation</a></li>
+ <li><a href="UPGRADE.html">Upgrade</a></li>
+ <li><a href="ChangeLog.html">ChangeLog</a></li>
+ <li><a href="http://semanticscuttle.sourceforget.net/">Homepage</a></li>
+ <li><a href="https://sourceforget.net/projects/semanticscuttle">Project page</a></li>
+</ul>
diff --git a/res/docs/style.css b/res/docs/style.css
new file mode 100644
index 0000000..a49b9c1
--- /dev/null
+++ b/res/docs/style.css
@@ -0,0 +1,25 @@
+/* SemanticScuttle improvements */
+h1.title {
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAsvSURBVGiBxZprjCRXdcd/p6r6Nd0979mHZ+3sCkfx4AdJsAhGm2BMYhAbrAgsEimKjGIlxELk8SkrQoQiSGgrCSJZh9hECsQ8hJCQlRDjYDsY4RAvRF6b9drN2t7HzOzOzmtnpl/V1fW4Jx+qu6emZ3pmbI/kI7Wq+9Ste///87j33FstqspeS7kkR4HPAAeAx4G/mDqu9T0fCJC9JlAuyXuB72Ymbklnxt9K/fxjmFblf4A7p45rc08HA6y97KxcksPAI5mJW9JDN99DbvI2Rt7+CSSVPwo8tJdjdWRPCQAPWZmhYuHn70LwyeQFOzvC4C/cDfB75ZL85h6Pt3cEyiW5B7gzf+T9ABRGM+SHHFIZQ3p8isz4TajyYLkkQ3s1JuwRgXJJ9gGfT49NkSpeQzYvpDMKxic/kkLUp3D9MaxUbhL4u70YsyN75YH7xcmN5q75FUQCCqNp0BaYFraE5IdTiJUmf+ROVLm3XJLb9mjcN06gXJJ3Avdk9/0iqDK0L4slAZgA1Af1yeaFVMaQGXsrqeKkGOWBckn2xHhvqJNySQQ4YWVHxRk8RCYvZHICptX1ACYmURhLo8Zj4OfegyXyy8C9bzoB4GPArZmxKYg8hvbn2lYP2sCDLgnHMQwMOtjZETLjN2IMnyuXZORNI1AuyU3A553CJOJkKY5ncZxog9W7V/XBtOKExid78Fbs9MCYUf71TSHQBv8tSeVzTnESJxVSnMgkgLfWwyhBxCJgcF8WEPJxKP1WuSSfLZdk8PUS2FUpUS7JAeCdwG3AMeBGsbOkhg5jpXNM3nQd6YEsiAU48VVsoH0VC7Db323WrtRorHr4Ky/TWnwejVot4HvAD4BngOemjmvrdRMol+Qg8OvAbwC/ChwGASuFlcphpQqIk0XEZuL6/QzuH2kD7AVub6lXtVi6sELgGRAhbMwTVGeJGgsYvwrgA6eAp4iLwf+dOq7+tgTKJbkF+Ggb9E3xbQssG7EcxE6D2IjYWKkU+fFBhg+MkhvO94DcgUj7atSisdKkWfXbRGzEstEoIGouE7qLhLU5ouYSQAP4IfBd4OGp41rtEnjpc+SBh4EPbe0kC7EtcsMFsoMFBkYK5EeKWI5DMiz6hctu9IGvePWAoBkReBFhAGK125mAsD5PULtEsHYOjVoV4ONTx/XrHQL/DPzRBrdYwsDwAPmRPAOjA2QLWcSSra2btHI//WsIL8TGRELLDWm5AX4jJAxBxAYUb/4U3sIpBd4+dVyfc4APdIAXxguMXjtKbjiHZW01QUWg7Y9YoB0gUft7r5UT+k7bThttA07q220tyyZXsMgVB0AswgBa9YD6VZfMvrfhLZwS4H3Acw5wBbgOIFvMkh/Nbx1JG8SAGiBMAEiAwtqlPtqsJ6mPDeA4NtagTW2xhb86DcBilaWp+ElOdGAtX1ymsdLYBYFer/QuWtuvBxv0Znf6lZkrBG4Fb/5ZWgGLv/sgMyIybgHfaIWcBEDh8guX8Ztbzli7INIuHbpg2wWdWS8pNul7wXafXddXrizjXl2jefkkGrp8v8wDl1fxgWtFVbnvDvmlj93B4xmHcYBMPsPhWw9jpTKQmoD0frAH25177U8LWpdiXV/pJKnD5tlod/pGxWPp3ApB5SJhbZZXF/jWXV/gi+0BPAfgwac4m0nxl39wO/9oWU4qdeiDVPQwwweuRTqdqqGbxGisswvgnoX6s+DP9/FKlIjpZPJaINH66r2FvtWIWHplkdBdIazNslLn2d/+Ig8mBlhxAFTVFZHv33CQv3/3DeHxsDKNHjpKo+pQGMkCJgathvUENhDWYw9N3A2RC9WT4L60BZH2MxomQDqsz1JRj/UjAs9w5cV5Qq9BUJnGC7jyx1/jr5o+Zt06TCfnyvP3/RuPlOf4qjf/f9TPPUqr5uKu1duDR20gHasaEI0BRY04pIbfCxO/E3tmS9GYxIaE3Vy1Rn6TuTMXCRprBJUZwkgbJ57gk6emqSY6e0VV/S4BVQ2BMx8+wZcurfBfjYtP0Jw7ibtap9VorpPoeiFK6NqhEC6DpODgH0L+5j4kkuGVTPo4adW0mDtzkVa1QtiYx6gJvvljPvnlp7mQePiSqi5ATzmtqi5Q/tAJ/na5xo9rZx8hqFygtrhGFAY9edDxSoIIGs8e3kzbGx8Ba6d1xazPSuqzfH6OxtU1Im8VNZF54gx//Tff4aeJB1aB850fm5ZbVb1a9zh3z5f4tOub2erZb2OCJtWFVbTXA0SgGv/uxnk7X7yLYGXhmvtg6NdAMjsQUZprNZbPz6GBCxpx5jJf/rNv8INEIxd4SRMl9JYbGlWdvrDMxa88zWej5mrUuPgkgesTND02JHHXI4ZNeYKBYAXcn8XhdOhPYfg9YOX6Urg6c7VrkEqTFz/6L3w9cdsHXmiHele225G9/MCTPLNc5ydB7TKqESYMEiAT4DeFVfJ+CM2XYyK5G2DyT+LwckY3DRj669gef4Gv9Mw4L6iq1/uM0w+9qqqIvCTgYhIzT8f6vSFDMg96pls1ENXiKVYccEZg7FgcVurH9/wl0qOD+P4FIneReovOQbACL6pufbq97Z5YVaPhAdZQAyaKc6BfyCRnpU0eSuiNB/5lcF+BxumYlHcJALt4mIHrbgfAGDpxPqOqq/0w9vVAt4HNsDgZVCNEeuM/4YEu4J6k3tCm10OJtlEL9eYIKi4gjBd1kHgnNr0tvp0IAAcklQcTYdusg9guZDbptgK/+b6dEtTEZcdYIRwFmrrDqcOuCFhODtUIy5adwe8EuGv5iI3eM9iOgEaIZTM0EI62B9tWtiVQLkkKGBUnBxph2dtZOxE+m0gpuwkv26HtAYtChlF2cW61kwdGABE7jYhB+gF+LR7YcN9sIG070ClLBjKMA+k3SqAI8QmBSD/rbgTsey2aqw3ctRqRH5DOp8gP58gW03EObUkq7ltsUDWIWKQsBvaMAGLH1t9g1XUPGBPhrtSoLVUJ3BaqBtNaw/gNAncI92oVMORHcwzuK5IZcLYIL4NldQwBjr2HBERsxNq8iEVBQG2pSn25hgkCTFAnqM4QuUto1DkZFKx0ATs3Ri0coba4RibvMLS/SH4kF3u23a9lxTmgqjgWOUBExOktH14LgWx86cR63LlXaVBfqeFVXTSKCN0Fgso0xlvBGPzFKj86fYmny3PM3DGltx3ZV7u94NfeQnUWOzuK8YfxKnVsRyiO5ylMDJDJOSCdRdEQbwUBsIHXTWAJwAQNAs9nZfYqzaqL8QNM6BJUZwmrs2jk4Ycsn73Cv3/he3znmXOsdTp46CleBb7658e45f03R3fvG1w6Ks0lS1J5onSRVa/Jyqwhk0/hZKx4xTchrYCVBIG+shOBl4FaUJku2rkx6o0KUXM5PohtLqOqutrg1LMXefTTj/DDNbe/pe5/lNP3P8rpY29j/73v5oNHJhrvywSNiQgLK53HCzLxwa+JX46sNji3G4w7Hq+XS/IJVf5BBOnoWgGL5xZ57OEf8dh/PMdWu/mO+MQbkByw4R1ALo31qbt4x7uu5wMTg7zLknWgfsjyp77Nx//zeRaA09vVQrt6P/CZD8vv33CQo65P9acznP2n/+ZnftgtdXtFgWVgTlW7oSQiGeL/TlxDz+xy6xEGP/IObj48zlu8APeBJ3niJ+eptG8/r6oV+siuCIjIjRCfGW0jIfEx5WXV/i8nRESACWCSHq/0kZPb9bebWghgkf4E1oB5YElV+3mlK+3ibBFYFJECsVf298Gyth142KUHAERkEjgEpIA6cWwvbLVLeq0iIhYwRuyZQeKZZxV4VXXboz/+HwP+91Qbpr+OAAAAAElFTkSuQmCC");
+ background-repeat: no-repeat;
+ padding-left: 64px;
+ padding-top: 0.2em;
+ margin-bottom: 00px;
+ height: 60px;
+ border-bottom: 3px solid #666;
+}
+h2 {
+ margin-top: 1.5em;
+
+}
+pre {
+ padding: 1em;
+ background-color: #EEE;
+ border: 1px solid #BBB;
+ width: auto;
+}
+
+tt, code {
+ background-color: #DDD;
+ padding: 0.2ex;
+}
diff --git a/src/SemanticScuttle/Config.php b/src/SemanticScuttle/Config.php
new file mode 100644
index 0000000..0773310
--- /dev/null
+++ b/src/SemanticScuttle/Config.php
@@ -0,0 +1,109 @@
+<?php
+/**
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license AGPL http://www.gnu.org/licenses/agpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+
+/**
+ * Configuration handling
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license AGPL http://www.gnu.org/licenses/agpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+class SemanticScuttle_Config
+{
+ /**
+ * Prefix for configuration files.
+ * Used to inject stream wrapper protocol for unit testing
+ *
+ * @var string
+ */
+ public $filePrefix = '';
+
+
+
+ /**
+ * Finds the correct data directory
+ *
+ * @return string Full path to the data directory with a trailing slash
+ */
+ protected function getDataDir()
+ {
+ if ('@data_dir@' == '@' . 'data_dir@') {
+ //non pear-install
+ $datadir = dirname(__FILE__) . '/../../data/';
+ } else {
+ //pear installation; files are in include path
+ $datadir = '@data_dir@/SemanticScuttle/';
+ }
+
+ return $datadir;
+ }
+
+
+
+ /**
+ * Tries to find a configuration file by looking in different
+ * places:
+ * - pear data_dir/SemanticScuttle/config-$hostname.php
+ * - pear data_dir/SemanticScuttle/config.php
+ * - /etc/semanticscuttle/config-$hostname.php
+ * - /etc/semanticscuttle/config.php
+ *
+ * Paths with host name have priority.
+ *
+ * @return array Array with config file path as first value
+ * and default config file path as second value.
+ * Any may be NULL if not found
+ */
+ public function findFiles()
+ {
+ //use basename to prevent path injection
+ $host = basename($_SERVER['HTTP_HOST']);
+ $datadir = $this->getDataDir();
+
+ $arFiles = array(
+ $datadir . 'config.' . $host . '.php',
+ '/etc/semanticscuttle/config.' . $host . '.php',
+ $datadir . 'config.php',
+ '/etc/semanticscuttle/config.php',
+ );
+
+ $configfile = null;
+ foreach ($arFiles as $file) {
+ if (file_exists($this->filePrefix . $file)) {
+ $configfile = $file;
+ break;
+ }
+ }
+
+ //find default file
+ $arDefaultFiles = array_unique(
+ array(
+ substr($configfile, 0, -3) . 'default.php',
+ $datadir . 'config.default.php',
+ '/etc/semanticscuttle/config.default.php',
+ )
+ );
+ $defaultfile = null;
+ foreach ($arDefaultFiles as $file) {
+ if (file_exists($this->filePrefix . $file)) {
+ $defaultfile = $file;
+ break;
+ }
+ }
+ return array($configfile, $defaultfile);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/src/SemanticScuttle/Environment.php b/src/SemanticScuttle/Environment.php
new file mode 100644
index 0000000..e5fe3de
--- /dev/null
+++ b/src/SemanticScuttle/Environment.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * SemanticScuttle - your social bookmark manager.
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license AGPL http://www.gnu.org/licenses/agpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+
+/**
+ * Server environment handling methods
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license AGPL http://www.gnu.org/licenses/agpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+class SemanticScuttle_Environment
+{
+ /**
+ * Determines the correct $_SERVER['PATH_INFO'] value
+ *
+ * @return string New value
+ */
+ public static function getServerPathInfo()
+ {
+ /* old code that does not work today.
+ if you find that this code helps you, tell us
+ and send us the output of var_export($_SERVER);
+ // Correct bugs with PATH_INFO (maybe for Apache 1 or CGI) -- for 1&1 host...
+ if (isset($_SERVER['PATH_INFO']) && isset($_SERVER['ORIG_PATH_INFO'])) {
+ if (strlen($_SERVER["PATH_INFO"])<strlen($_SERVER["ORIG_PATH_INFO"])) {
+ $_SERVER["PATH_INFO"] = $_SERVER["ORIG_PATH_INFO"];
+ }
+ if (strcasecmp($_SERVER["PATH_INFO"], $_SERVER["SCRIPT_NAME"]) == 0) {
+ unset($_SERVER["PATH_INFO"]);
+ }
+ if (strpos($_SERVER["PATH_INFO"], '.php') !== false) {
+ unset($_SERVER["PATH_INFO"]);
+ }
+ }
+ */
+
+ return $_SERVER['PATH_INFO'];
+ }
+}
+?> \ No newline at end of file
diff --git a/src/SemanticScuttle/Model/Bookmark.php b/src/SemanticScuttle/Model/Bookmark.php
index 8bda0b3..1330642 100644
--- a/src/SemanticScuttle/Model/Bookmark.php
+++ b/src/SemanticScuttle/Model/Bookmark.php
@@ -24,6 +24,23 @@
class SemanticScuttle_Model_Bookmark
{
/**
+ * Status "public" / visible for all
+ */
+ const SPUBLIC = 0;
+
+ /**
+ * Status "shared" / visible for people on your watchlist
+ */
+ const SWATCHLIST = 1;
+
+ /**
+ * Status "private" / visible for yourself only
+ */
+ const SPRIVATE = 2;
+
+
+
+ /**
* Checks if the given URL is valid and may be used with this
* SemanticScuttle installation.
*
diff --git a/src/SemanticScuttle/Model/User.php b/src/SemanticScuttle/Model/User.php
index 500f5b1..3aa617b 100644
--- a/src/SemanticScuttle/Model/User.php
+++ b/src/SemanticScuttle/Model/User.php
@@ -35,6 +35,7 @@ class SemanticScuttle_Model_User
var $content;
var $datetime;
var $isAdmin;
+ var $privateKey;
/**
* Create a new user object
@@ -69,6 +70,29 @@ class SemanticScuttle_Model_User
}
/**
+ * Returns private key
+ *
+ * @param boolean return sanitized value which basically drops
+ * leading dash if exists
+ *
+ * @return string private key
+ */
+ public function getPrivateKey($sanitized = false)
+ {
+ // Look for value only if not already set
+ if (!isset($this->privateKey)) {
+ $us = SemanticScuttle_Service_Factory::get('User');
+ $user = $us->getUser($this->id);
+ $this->privateKey = $user['privateKey'];
+ }
+ if ($sanitized == true) {
+ return substr($this->privateKey, -32);
+ } else {
+ return $this->privateKey;
+ }
+ }
+
+ /**
* Returns full user name as specified in the profile.
*
* @return string Full name
@@ -182,4 +206,4 @@ class SemanticScuttle_Model_User
}
}
-?> \ No newline at end of file
+?>
diff --git a/src/SemanticScuttle/Service/Bookmark.php b/src/SemanticScuttle/Service/Bookmark.php
index 919ca7a..17ab7ba 100644
--- a/src/SemanticScuttle/Service/Bookmark.php
+++ b/src/SemanticScuttle/Service/Bookmark.php
@@ -427,6 +427,7 @@ class SemanticScuttle_Service_Bookmark extends SemanticScuttle_DbService
$existence[$hashes[$row['bHash']]] = $row['count'] > 0;
}
+ $this->db->sql_freeresult($dbresult);
return $existence;
}
diff --git a/src/SemanticScuttle/Service/Bookmark2Tag.php b/src/SemanticScuttle/Service/Bookmark2Tag.php
index a10cb61..04ee43d 100644
--- a/src/SemanticScuttle/Service/Bookmark2Tag.php
+++ b/src/SemanticScuttle/Service/Bookmark2Tag.php
@@ -99,7 +99,7 @@ class SemanticScuttle_Service_Bookmark2Tag extends SemanticScuttle_DbService
$tags_count = is_array($tags)?count($tags):0;
for ($i = 0; $i < $tags_count; $i++) {
- $tags[$i] = trim(strtolower($tags[$i]));
+ $tags[$i] = trim(utf8_strtolower($tags[$i]));
if ($fromApi) {
include_once 'SemanticScuttle/functions.php';
$tags[$i] = convertTag($tags[$i], 'in');
@@ -584,7 +584,7 @@ class SemanticScuttle_Service_Bookmark2Tag extends SemanticScuttle_DbService
if (is_int($days)) {
$query .= ' AND B.bDatetime > "'
- . date('Y-m-d H:i:s', time() - (86400 * $days))
+ . gmdate('Y-m-d H:i:s', time() - (86400 * $days))
. '"';
}
diff --git a/src/SemanticScuttle/Service/Tag.php b/src/SemanticScuttle/Service/Tag.php
index 25d3888..8325285 100644
--- a/src/SemanticScuttle/Service/Tag.php
+++ b/src/SemanticScuttle/Service/Tag.php
@@ -141,10 +141,10 @@ class SemanticScuttle_Service_Tag extends SemanticScuttle_DbService
//normalize
if(!is_array($tags)) {
- $tags = strtolower(trim($tags));
+ $tags = utf8_strtolower(trim($tags));
} else {
for($i=0; $i<count($tags); $i++) {
- $tags[$i] = strtolower(trim($tags[$i]));
+ $tags[$i] = utf8_strtolower(trim($tags[$i]));
}
}
return $tags;
diff --git a/src/SemanticScuttle/Service/User.php b/src/SemanticScuttle/Service/User.php
index 0e437c2..7550ed2 100644
--- a/src/SemanticScuttle/Service/User.php
+++ b/src/SemanticScuttle/Service/User.php
@@ -48,9 +48,10 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
protected $currentuser = null;
protected $fields = array(
- 'primary' => 'uId',
- 'username' => 'username',
- 'password' => 'password'
+ 'primary' => 'uId',
+ 'username' => 'username',
+ 'password' => 'password',
+ 'privateKey' => 'privateKey'
);
protected $profileurl;
@@ -215,6 +216,18 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
return $this->_getuser($this->getFieldName('username'), $username);
}
+ /**
+ * Returns user row from database.
+ *
+ * @param string $privateKey Private Key
+ *
+ * @return array User array from database, false if no user was found
+ */
+ public function getUserByPrivateKey($privateKey)
+ {
+ return $this->_getuser($this->getFieldName('privateKey'), $privateKey);
+ }
+
function getObjectUserByUsername($username) {
$user = $this->_getuser($this->getFieldName('username'), $username);
if($user != false) {
@@ -280,6 +293,22 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
}
/**
+ * Tells you if the private key is enabled and valid
+ *
+ * @param string $privateKey Private Key
+ *
+ * @return boolean True if enabled and valid
+ */
+ public function isPrivateKeyValid($privateKey)
+ {
+ // check length of private key
+ if (strlen($privateKey) == 32) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Returns the current user object
*
* @param boolean $refresh Reload the user from database
@@ -293,7 +322,7 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
{
if (!is_null($newval)) {
//internal use only: reset currentuser
- $currentuser = $newval;
+ $this->currentuser = $newval;
} else if ($refresh || !isset($this->currentuser)) {
if ($id = $this->getCurrentUserId()) {
$this->currentuser = $this->getUser($id);
@@ -510,6 +539,46 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
}
/**
+ * Try to authenticate via the privateKey
+ *
+ * @param string $privateKey Private Key
+ *
+ * @return boolean true if the user could be authenticated,
+ * false if not.
+ */
+ public function loginPrivateKey($privateKey)
+ {
+ /* Check if private key valid and enabled */
+ if (!$this->isPrivateKeyValid($privateKey)) {
+ return false;
+ }
+
+ $query = 'SELECT '. $this->getFieldName('primary') .' FROM '
+ . $this->getTableName() .' WHERE '
+ . $this->getFieldName('privateKey') .' = "'
+ . $this->db->sql_escape($privateKey) .'"';
+
+ if (!($dbresult = $this->db->sql_query($query))) {
+ message_die(
+ GENERAL_ERROR,
+ 'Could not get user',
+ '', __LINE__, __FILE__, $query, $this->db
+ );
+ return false;
+ }
+
+ $row = $this->db->sql_fetchrow($dbresult);
+ $this->db->sql_freeresult($dbresult);
+
+ if ($row) {
+ $this->setCurrentUserId($row[$this->getFieldName('primary')], false);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
* Logs the user off
*
* @return void
@@ -519,7 +588,8 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
@setcookie($this->getCookiekey(), '', time() - 1, '/');
unset($_COOKIE[$this->getCookiekey()]);
session_unset();
- $this->getCurrentUser(TRUE, false);
+ $this->currentuserId = null;
+ $this->currentuser = null;
}
function getWatchlist($uId) {
@@ -603,11 +673,12 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
return false;
}
- $arrWatch = array();
+ $retval = true;
if ($this->db->sql_numrows($dbresult) == 0)
- return false;
- else
- return true;
+ $retval = false;
+
+ $this->db->sql_freeresult($dbresult);
+ return $retval;
}
function setWatchStatus($subjectUserID) {
@@ -646,24 +717,26 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
* No checks are done in here - you ought to have checked
* everything before calling this method!
*
- * @param string $username Username to use
- * @param string $password Password to use
- * @param string $email Email to use
+ * @param string $username Username to use
+ * @param string $password Password to use
+ * @param string $email Email to use
+ * @param string $privateKey Key for RSS auth
*
* @return mixed Integer user ID if all is well,
* boolean false if an error occured
*/
- public function addUser($username, $password, $email)
+ public function addUser($username, $password, $email, $privateKey = null)
{
// Set up the SQL UPDATE statement.
$datetime = gmdate('Y-m-d H:i:s', time());
$password = $this->sanitisePassword($password);
$values = array(
- 'username' => $username,
- 'password' => $password,
- 'email' => $email,
- 'uDatetime' => $datetime,
- 'uModified' => $datetime
+ 'username' => $username,
+ 'password' => $password,
+ 'email' => $email,
+ 'uDatetime' => $datetime,
+ 'uModified' => $datetime,
+ 'privateKey' => $privateKey
);
$sql = 'INSERT INTO '. $this->getTableName()
. ' '. $this->db->sql_build_array('INSERT', $values);
@@ -687,40 +760,64 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
/**
* Updates the given user
*
- * @param integer $uId ID of user to change
- * @param string $password Password to use
- * @param string $name Realname to use
- * @param string $email Email to use
- * @param string $homepage User's homepage
- * @param string $uContent User note
+ * @param integer $uId ID of user to change
+ * @param string $password Password to use
+ * @param string $name Realname to use
+ * @param string $email Email to use
+ * @param string $homepage User's homepage
+ * @param string $uContent User note
+ * @param string $privateKey RSS Private Key
+ * @param boolean $enablePrivateKey RSS Private Key Flag
*
* @return boolean True when all is well, false if not
*/
public function updateUser(
- $uId, $password, $name, $email, $homepage, $uContent
+ $uId, $password, $name, $email, $homepage, $uContent,
+ $privateKey = null, $enablePrivateKey = false
) {
if (!is_numeric($uId)) {
return false;
}
+ // prepend '-' to privateKey if disabled
+ if ($privateKey != null && strlen($privateKey) == 32
+ && $enablePrivateKey == false
+ ) {
+ $privateKey = '-' . $privateKey;
+ }
+
+ // remove '-' from privateKey if enabling
+ if ($privateKey != null && strlen($privateKey) == 33
+ && $enablePrivateKey == true
+ ) {
+ $privateKey = substr($privateKey, 1, 32);
+ }
+
+ // if new user is enabling Private Key, create new key
+ if ($privateKey == null && $enablePrivateKey == true) {
+ $privateKey = $this->getNewPrivateKey();
+ }
+
// Set up the SQL UPDATE statement.
$moddatetime = gmdate('Y-m-d H:i:s', time());
if ($password == '') {
$updates = array(
- 'uModified' => $moddatetime,
- 'name' => $name,
- 'email' => $email,
- 'homepage' => $homepage,
- 'uContent' => $uContent
+ 'uModified' => $moddatetime,
+ 'name' => $name,
+ 'email' => $email,
+ 'homepage' => $homepage,
+ 'uContent' => $uContent,
+ 'privateKey' => $privateKey
);
} else {
$updates = array(
- 'uModified' => $moddatetime,
- 'password' => $this->sanitisePassword($password),
- 'name' => $name,
- 'email' => $email,
- 'homepage' => $homepage,
- 'uContent' => $uContent
+ 'uModified' => $moddatetime,
+ 'password' => $this->sanitisePassword($password),
+ 'name' => $name,
+ 'email' => $email,
+ 'homepage' => $homepage,
+ 'uContent' => $uContent,
+ 'privateKey' => $privateKey
);
}
$sql = 'UPDATE '. $this->getTableName()
@@ -837,6 +934,56 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService
}
}
+ /**
+ * Generates a new private key and confirms it isn't being used.
+ * Private key is 32 characters long, consisting of lowercase and
+ * numeric characters.
+ *
+ * @return string the new key value
+ */
+ public function getNewPrivateKey()
+ {
+ do {
+ $newKey = md5(uniqid('SemanticScuttle', true));
+ } while ($this->privateKeyExists($newKey));
+
+ return $newKey;
+ }
+
+ /**
+ * Checks if a private key already exists
+ *
+ * @param string $privateKey key that has been generated
+ *
+ * @return boolean true when the private key exists,
+ * False if not.
+ */
+ public function privateKeyExists($privateKey)
+ {
+ if (!$privateKey) {
+ return false;
+ }
+ $crit = array('privateKey' => $privateKey);
+
+ $sql = 'SELECT COUNT(*) as "0" FROM '
+ . $GLOBALS['tableprefix'] . 'users'
+ . ' WHERE '. $this->db->sql_build_array('SELECT', $crit);
+
+ if (!($dbresult = $this->db->sql_query($sql))) {
+ message_die(
+ GENERAL_ERROR, 'Could not get vars', '',
+ __LINE__, __FILE__, $sql, $this->db
+ );
+ }
+ if ($this->db->sql_fetchfield(0, 0) > 0) {
+ $exists = true;
+ } else {
+ $exists = false;
+ }
+ $this->db->sql_freeresult($dbresult);
+ return $exists;
+ }
+
function isReserved($username) {
if (in_array($username, $GLOBALS['reservedusers'])) {
return true;
diff --git a/src/SemanticScuttle/constants.php b/src/SemanticScuttle/constants.php
index f8567d9..fcb2d90 100644
--- a/src/SemanticScuttle/constants.php
+++ b/src/SemanticScuttle/constants.php
@@ -69,16 +69,6 @@ define('PAGE_WATCHLIST', "watchlist");
// installations on the same host server
define('INSTALLATION_ID', md5($GLOBALS['dbname'].$GLOBALS['tableprefix']));
-// Correct bugs with PATH_INFO (maybe for Apache 1 or CGI) -- for 1&1 host...
-if (isset($_SERVER['PATH_INFO']) && isset($_SERVER['ORIG_PATH_INFO'])) {
- if (strlen($_SERVER["PATH_INFO"])<strlen($_SERVER["ORIG_PATH_INFO"])) {
- $_SERVER["PATH_INFO"] = $_SERVER["ORIG_PATH_INFO"];
- }
- if (strcasecmp($_SERVER["PATH_INFO"], $_SERVER["SCRIPT_NAME "]) == 0) {
- unset($_SERVER["PATH_INFO"]);
- }
- if (strpos($_SERVER["PATH_INFO"], '.php') !== false) {
- unset($_SERVER["PATH_INFO"]);
- }
-}
+//currently not needed
+//$_SERVER['PATH_INFO'] = SemanticScuttle_Environment::getServerPathInfo();
?>
diff --git a/src/SemanticScuttle/header.php b/src/SemanticScuttle/header.php
index 6c0d4df..694df54 100644
--- a/src/SemanticScuttle/header.php
+++ b/src/SemanticScuttle/header.php
@@ -25,8 +25,20 @@ if ('@data_dir@' == '@' . 'data_dir@') {
//FIXME: when you have multiple installations, the www_dir will be wrong
$wwwdir = '@www_dir@/SemanticScuttle/';
}
+require_once dirname(__FILE__) . '/Environment.php';
+require_once dirname(__FILE__) . '/Config.php';
-if (!file_exists($datadir . '/config.php')) {
+$cfg = new SemanticScuttle_Config();
+list($configfile, $defaultfile) = $cfg->findFiles();
+if ($defaultfile === null) {
+ header('HTTP/1.0 500 Internal Server Error');
+ die(
+ 'No default configuration file config.default.php found.'
+ . ' This is really, really strange'
+ . "\n"
+ );
+}
+if ($configfile === null) {
header('HTTP/1.0 500 Internal Server Error');
die(
'Please copy "config.php.dist" to "config.php" in data/ folder.'
@@ -39,8 +51,8 @@ set_include_path(
);
// 1 // First requirements part (before debug management)
-require_once $datadir . '/config.default.php';
-require_once $datadir . '/config.php';
+require_once $defaultfile;
+require_once $configfile;
if (isset($_GET['unittestMode']) && $_GET['unittestMode'] == 1
) {
diff --git a/tests/AllTests.php b/tests/AllTests.php
index 9e825e8..92f8960 100644
--- a/tests/AllTests.php
+++ b/tests/AllTests.php
@@ -46,6 +46,7 @@ class AllTests extends PHPUnit_Framework_TestSuite
$suite->addTestFile($tdir . '/VoteTest.php');
$suite->addTestFile($tdir . '/UserTest.php');
$suite->addTestFile($tdir . '/Api/ExportCsvTest.php');
+ $suite->addTestFile($tdir . '/Api/OpenSearchTest.php');
$suite->addTestFile($tdir . '/Api/PostsAddTest.php');
$suite->addTestFile($tdir . '/Api/PostsDeleteTest.php');
$suite->addTestFile($tdir . '/Api/PostsUpdateTest.php');
@@ -58,4 +59,4 @@ class AllTests extends PHPUnit_Framework_TestSuite
{
}
}
-?> \ No newline at end of file
+?>
diff --git a/tests/Api/PostsAddTest.php b/tests/Api/PostsAddTest.php
index 02e2b38..e6d0531 100644
--- a/tests/Api/PostsAddTest.php
+++ b/tests/Api/PostsAddTest.php
@@ -108,7 +108,7 @@ TXT;
$this->assertEquals($bmUrl, $bm['bAddress']);
$this->assertEquals($bmTitle, $bm['bTitle']);
- $this->assertEquals($bmDescription, $bm['bDescription']);
+ $this->assertEquals($bmDescription, stripslashes($bm['bDescription']));
$this->assertEquals($bmTags, $bm['tags']);
$this->assertEquals(
gmdate('Y-m-d H:i:s', strtotime($bmDatetime)),
@@ -170,7 +170,7 @@ TXT;
$this->assertEquals($bmUrl, $bm['bAddress']);
$this->assertEquals($bmTitle, $bm['bTitle']);
- $this->assertEquals($bmDescription, $bm['bDescription']);
+ $this->assertEquals($bmDescription, stripslashes($bm['bDescription']));
$this->assertEquals($bmTags, $bm['tags']);
$this->assertEquals(
gmdate('Y-m-d H:i:s', strtotime($bmDatetime)),
diff --git a/tests/Bookmark2TagTest.php b/tests/Bookmark2TagTest.php
index 789540f..0236a5f 100644
--- a/tests/Bookmark2TagTest.php
+++ b/tests/Bookmark2TagTest.php
@@ -282,10 +282,10 @@ class Bookmark2TagTest extends TestBase
public function testGetPopularTagsDays()
{
$user = $this->addUser();
- $this->addTagBookmark($user, array('one', 'two'), 'today');
- $this->addTagBookmark($user, array('one', 'thr'), 'today');
- $this->addTagBookmark($user, array('one', 'two'), '-1 day 1 hour');
- $this->addTagBookmark($user, array('one', 'thr'), '-3 days 1 hour');
+ $this->addTagBookmark($user, array('one', 'two'), 'now');
+ $this->addTagBookmark($user, array('one', 'thr'), 'now');
+ $this->addTagBookmark($user, array('one', 'two'), '-1 day -1 hour');
+ $this->addTagBookmark($user, array('one', 'thr'), '-3 days -1 hour');
$arTags = $this->b2ts->getPopularTags(null, 10, null, 1);
$this->assertInternalType('array', $arTags);
@@ -608,4 +608,4 @@ class Bookmark2TagTest extends TestBase
$this->assertContains(array('tag' => 'usable', 'bCount' => '2'), $arTags);
}
}
-?> \ No newline at end of file
+?>
diff --git a/tests/BookmarkTest.php b/tests/BookmarkTest.php
index b50dab2..44a82d9 100644
--- a/tests/BookmarkTest.php
+++ b/tests/BookmarkTest.php
@@ -1330,5 +1330,51 @@ class BookmarkTest extends TestBase
+ /**
+ * Test private bookmarks
+ *
+ * @return void
+ */
+ public function testPrivateBookmarks()
+ {
+ $uid = $this->addUser();
+ /* create private bookmark */
+ $this->bs->addBookmark(
+ 'http://test', 'test', 'desc', 'note',
+ 2,//private
+ array(), null, null, false, false, $uid
+ );
+ /* create public bookmark */
+ $this->bs->addBookmark(
+ 'http://example.org', 'title', 'desc', 'priv',
+ 0,//public
+ array(), null, null, false, false, $uid
+ );
+
+ $this->assertEquals(1, $this->bs->countBookmarks($uid, 'public'));
+ $this->assertEquals(1, $this->bs->countBookmarks($uid, 'private'));
+ $this->assertEquals(0, $this->bs->countBookmarks($uid, 'shared'));
+ $this->assertEquals(2, $this->bs->countBookmarks($uid, 'all'));
+
+ $this->us->setCurrentUserId($uid);
+ $bookmarks = $this->bs->getBookmarks();
+ // first record should be private bookmark
+ $b0 = $bookmarks['bookmarks'][0];
+ $this->assertEquals('test', $b0['bTitle']);
+ // second record should be public bookmark
+ $b0 = $bookmarks['bookmarks'][1];
+ $this->assertEquals('title', $b0['bTitle']);
+
+ // test non authenticated query
+ $this->us->setCurrentUserId(null);
+ $bookmarks = $this->bs->getBookmarks();
+ // should only result in one link - public
+ $b2 = $bookmarks['bookmarks'][0];
+ $this->assertEquals('title', $b2['bTitle']);
+ // there should be no second record
+ $this->assertEquals(1,count($bookmarks['bookmarks']));
+
+ }
+
}
?>
diff --git a/tests/SemanticScuttle/ConfigTest.php b/tests/SemanticScuttle/ConfigTest.php
new file mode 100644
index 0000000..670f82a
--- /dev/null
+++ b/tests/SemanticScuttle/ConfigTest.php
@@ -0,0 +1,206 @@
+<?php
+//that's PEAR's Stream_Var package
+require_once 'Stream/Var.php';
+
+class SemanticScuttle_ConfigTest_StreamVar extends Stream_Var {
+ public function url_stat($path, $flags)
+ {
+ $url = parse_url($path);
+
+ $scope = $url['host'];
+ if (isset($url['path'])) {
+ $varpath = substr($url['path'], 1);
+ } else {
+ $varpath = '';
+ }
+
+ if (!$this->_setPointer($scope, $varpath)) {
+ return false;
+ }
+
+ return parent::url_stat($path, $flags);
+ }
+}
+
+class SemanticScuttle_ConfigTest extends PHPUnit_Framework_TestCase
+{
+ /**
+ * Configuration object to test
+ */
+ protected $cfg;
+
+
+ public function setUpWrapper()
+ {
+ if (!in_array('unittest', stream_get_wrappers())) {
+ stream_wrapper_register(
+ 'unittest', 'SemanticScuttle_ConfigTest_StreamVar'
+ );
+ }
+
+ $this->cfg = $this->getMock(
+ 'SemanticScuttle_Config',
+ array('getDataDir')
+ );
+ $this->cfg->expects($this->once())
+ ->method('getDataDir')
+ ->will($this->returnValue('/data-dir/'));
+
+ $this->cfg->filePrefix = 'unittest://GLOBALS/unittest-dir';
+ }
+
+
+
+ public function testFindLocalData()
+ {
+ $this->setUpWrapper();
+ $GLOBALS['unittest-dir']['data-dir'] = array(
+ 'config.php' => 'content',
+ 'config.default.php' => 'content'
+ );
+ $this->assertEquals(
+ array(
+ '/data-dir/config.php',
+ '/data-dir/config.default.php'
+ ),
+ $this->cfg->findFiles()
+ );
+ }
+
+ public function testFindHostPreferredOverNonHostConfig()
+ {
+ $this->setUpWrapper();
+ $_SERVER['HTTP_HOST'] = 'foo.example.org';
+
+ $GLOBALS['unittest-dir']['data-dir'] = array(
+ 'config.php' => 'content',
+ 'config.foo.example.org.php' => 'content',
+ 'config.default.php' => 'content'
+ );
+ $this->assertEquals(
+ array(
+ '/data-dir/config.foo.example.org.php',
+ '/data-dir/config.default.php'
+ ),
+ $this->cfg->findFiles()
+ );
+ }
+
+ public function testFindEtcHostPreferredOverLocalConfigPhp()
+ {
+ $this->setUpWrapper();
+ $_SERVER['HTTP_HOST'] = 'foo.example.org';
+
+ $GLOBALS['unittest-dir'] = array(
+ 'etc' => array(
+ 'semanticscuttle' => array(
+ 'config.foo.example.org.php' => 'content',
+ )
+ ),
+ 'data-dir' => array(
+ 'config.php' => 'content',
+ 'config.default.php' => 'content'
+ )
+ );
+
+ $this->assertEquals(
+ array(
+ '/etc/semanticscuttle/config.foo.example.org.php',
+ '/data-dir/config.default.php'
+ ),
+ $this->cfg->findFiles()
+ );
+ }
+
+ public function testFindEtcConfig()
+ {
+ $this->setUpWrapper();
+ $GLOBALS['unittest-dir'] = array(
+ 'etc' => array(
+ 'semanticscuttle' => array(
+ 'config.php' => 'content'
+ )
+ ),
+ 'data-dir' => array(
+ 'config.default.php' => 'content'
+ )
+ );
+ $this->assertEquals(
+ array(
+ '/etc/semanticscuttle/config.php',
+ '/data-dir/config.default.php'
+ ),
+ $this->cfg->findFiles()
+ );
+ }
+
+ public function testFindEtcDefaultConfig()
+ {
+ $this->setUpWrapper();
+ $GLOBALS['unittest-dir'] = array(
+ 'etc' => array(
+ 'semanticscuttle' => array(
+ 'config.php' => 'content',
+ 'config.default.php' => 'content'
+ )
+ ),
+ );
+ $this->assertEquals(
+ array(
+ '/etc/semanticscuttle/config.php',
+ '/etc/semanticscuttle/config.default.php'
+ ),
+ $this->cfg->findFiles()
+ );
+ }
+
+ public function testFindLocalDefaultPreferredOverEtcDefault()
+ {
+ $this->setUpWrapper();
+ $GLOBALS['unittest-dir'] = array(
+ 'etc' => array(
+ 'semanticscuttle' => array(
+ 'config.php' => 'content',
+ 'config.default.php' => 'content'
+ )
+ ),
+ 'data-dir' => array(
+ 'config.php' => 'content',
+ 'config.default.php' => 'content'
+ )
+ );
+ $this->assertEquals(
+ array(
+ '/data-dir/config.php',
+ '/data-dir/config.default.php'
+ ),
+ $this->cfg->findFiles()
+ );
+ }
+
+ public function testFindSameDirDefaultPreferred()
+ {
+ $this->setUpWrapper();
+ $GLOBALS['unittest-dir'] = array(
+ 'etc' => array(
+ 'semanticscuttle' => array(
+ 'config.php' => 'content',
+ 'config.default.php' => 'content'
+ )
+ ),
+ 'data-dir' => array(
+ 'config.default.php' => 'content'
+ )
+ );
+ $this->assertEquals(
+ array(
+ '/etc/semanticscuttle/config.php',
+ '/etc/semanticscuttle/config.default.php'
+ ),
+ $this->cfg->findFiles()
+ );
+ }
+
+}
+
+?> \ No newline at end of file
diff --git a/tests/SemanticScuttle/EnvironmentTest.php b/tests/SemanticScuttle/EnvironmentTest.php
new file mode 100644
index 0000000..a41efa1
--- /dev/null
+++ b/tests/SemanticScuttle/EnvironmentTest.php
@@ -0,0 +1,95 @@
+<?php
+
+class SemanticScuttle_EnvironmentTest extends PHPUnit_Framework_TestCase
+{
+ public function testServerPathInfoModPhp()
+ {
+ $_SERVER = array(
+ 'HTTP_USER_AGENT' => 'Opera/9.80 (X11; Linux x86_64; U; de) Presto/2.9.168 Version/11.50',
+ 'HTTP_HOST' => 'bm-cgi.bogo',
+ 'HTTP_ACCEPT' => 'text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1',
+ 'HTTP_ACCEPT_LANGUAGE' => 'de-DE,de;q=0.9,en;q=0.8',
+ 'HTTP_ACCEPT_ENCODING' => 'gzip, deflate',
+ 'HTTP_COOKIE' => 'PHPSESSID=ga446jhs0e09hkt60u9bsmp0n0',
+ 'HTTP_CACHE_CONTROL' => 'no-cache',
+ 'HTTP_CONNECTION' => 'Keep-Alive',
+ 'PATH' => '/usr/local/bin:/usr/bin:/bin',
+ 'SERVER_SIGNATURE' => '<address>Apache/2.2.17 (Ubuntu) Server at bm-cgi.bogo Port 80</address>',
+ 'SERVER_SOFTWARE' => 'Apache/2.2.17 (Ubuntu)',
+ 'SERVER_NAME' => 'bm-cgi.bogo',
+ 'SERVER_ADDR' => '127.0.0.1',
+ 'SERVER_PORT' => '80',
+ 'REMOTE_ADDR' => '127.0.0.1',
+ 'DOCUMENT_ROOT' => '/etc/apache2/htdocs',
+ 'SERVER_ADMIN' => '[no address given]',
+ 'SCRIPT_FILENAME' => '/home/cweiske/Dev/html/hosts/bm-cgi.bogo/profile.php',
+ 'REMOTE_PORT' => '45349',
+ 'GATEWAY_INTERFACE' => 'CGI/1.1',
+ 'SERVER_PROTOCOL' => 'HTTP/1.1',
+ 'REQUEST_METHOD' => 'GET',
+ 'QUERY_STRING' => '',
+ 'REQUEST_URI' => '/profile.php/dummy',
+ 'SCRIPT_NAME' => '/profile.php',
+ 'PATH_INFO' => '/dummy',
+ 'PATH_TRANSLATED' => '/home/cweiske/Dev/html/hosts/bm-cgi.bogo/dummy',
+ 'PHP_SELF' => '/profile.php/dummy',
+ 'REQUEST_TIME' => 1311422546,
+ );
+ $this->assertEquals(
+ '/dummy', SemanticScuttle_Environment::getServerPathInfo()
+ );
+ }
+
+
+ public function testServerPathInfoFastCgi()
+ {
+ $_SERVER = array(
+ 'PHP_FCGI_MAX_REQUESTS' => '5000',
+ 'PHPRC' => '/etc/php5/cgi/5.3.6/',
+ 'PHP_FCGI_CHILDREN' => '3',
+ 'PWD' => '/var/www/cgi-bin',
+ 'FCGI_ROLE' => 'RESPONDER',
+ 'REDIRECT_HANDLER' => 'php-cgi',
+ 'REDIRECT_STATUS' => '200',
+ 'HTTP_USER_AGENT' => 'Opera/9.80 (X11; Linux x86_64; U; de) Presto/2.9.168 Version/11.50',
+ 'HTTP_HOST' => 'bm-cgi.bogo',
+ 'HTTP_ACCEPT' => 'text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1',
+ 'HTTP_ACCEPT_LANGUAGE' => 'de-DE,de;q=0.9,en;q=0.8',
+ 'HTTP_ACCEPT_ENCODING' => 'gzip, deflate',
+ 'HTTP_COOKIE' => 'PHPSESSID=ga446jhs0e09hkt60u9bsmp0n0',
+ 'HTTP_CONNECTION' => 'Keep-Alive',
+ 'PATH' => '/usr/local/bin:/usr/bin:/bin',
+ 'SERVER_SIGNATURE' => '<address>Apache/2.2.17 (Ubuntu) Server at bm-cgi.bogo Port 80</address>',
+ 'SERVER_SOFTWARE' => 'Apache/2.2.17 (Ubuntu)',
+ 'SERVER_NAME' => 'bm-cgi.bogo',
+ 'SERVER_ADDR' => '127.0.0.1',
+ 'SERVER_PORT' => '80',
+ 'REMOTE_ADDR' => '127.0.0.1',
+ 'DOCUMENT_ROOT' => '/etc/apache2/htdocs',
+ 'SERVER_ADMIN' => '[no address given]',
+ 'SCRIPT_FILENAME' => '/home/cweiske/Dev/html/hosts/bm-cgi.bogo/profile.php',
+ 'REMOTE_PORT' => '45342',
+ 'REDIRECT_URL' => '/profile.php/dummy',
+ 'GATEWAY_INTERFACE' => 'CGI/1.1',
+ 'SERVER_PROTOCOL' => 'HTTP/1.1',
+ 'REQUEST_METHOD' => 'GET',
+ 'QUERY_STRING' => '',
+ 'REQUEST_URI' => '/profile.php/dummy',
+ 'SCRIPT_NAME' => '/profile.php',
+ 'PATH_INFO' => '/dummy',
+ 'PATH_TRANSLATED' => '/etc/apache2/htdocs/dummy',
+ 'ORIG_PATH_INFO' => '/profile.php/dummy',
+ 'ORIG_SCRIPT_NAME' => '/cgi-bin-php/php-cgi-5.3.6',
+ 'ORIG_SCRIPT_FILENAME' => '/var/www/cgi-bin/php-cgi-5.3.6',
+ 'ORIG_PATH_TRANSLATED' => '/home/cweiske/Dev/html/hosts/bm-cgi.bogo/profile.php/dummy',
+ 'PHP_SELF' => '/profile.php/dummy',
+ 'REQUEST_TIME' => 1311422521,
+ );
+ $this->assertEquals(
+ '/dummy', SemanticScuttle_Environment::getServerPathInfo()
+ );
+ }
+
+}
+
+?> \ No newline at end of file
diff --git a/tests/Tag2TagTest.php b/tests/Tag2TagTest.php
index 0b73864..58556f1 100644
--- a/tests/Tag2TagTest.php
+++ b/tests/Tag2TagTest.php
@@ -332,6 +332,7 @@ class Tag2TagTest extends TestBase
$this->assertSame('B3', $results['bookmarks'][0]['bTitle']);
$results = $bs->getBookmarks(0, NULL, 1, 'aa+ee');
+
$this->assertSame(1, intval($results['total']));
$this->assertSame('B2', $results['bookmarks'][0]['bTitle']);
diff --git a/tests/TestBase.php b/tests/TestBase.php
index 095f32d..2914749 100644
--- a/tests/TestBase.php
+++ b/tests/TestBase.php
@@ -76,16 +76,18 @@ class TestBase extends PHPUnit_Framework_TestCase
/**
* Creates a new user in the database.
*
- * @param string $username Username
- * @param string $password Password
+ * @param string $username Username, may be null
+ * @param string $password Password, may be null
+ * @param mixed $privateKey String private key or boolean true to generate one
*
* @return integer ID of user
*
* @uses addUserData()
*/
- protected function addUser($username = null, $password = null)
- {
- return reset($this->addUserData($username, $password));
+ protected function addUser(
+ $username = null, $password = null, $privateKey = null
+ ) {
+ return reset($this->addUserData($username, $password, $privateKey));
}
@@ -93,13 +95,15 @@ class TestBase extends PHPUnit_Framework_TestCase
/**
* Creates a new user in the database and returns id, username and password.
*
- * @param string $username Username
- * @param string $password Password
+ * @param string $username Username, may be null
+ * @param string $password Password, may be null
+ * @param mixed $privateKey String private key or boolean true to generate one
*
- * @return array ID of user, Name of user, password of user
+ * @return array ID of user, Name of user, password of user, privateKey
*/
- protected function addUserData($username = null, $password = null)
- {
+ protected function addUserData(
+ $username = null, $password = null, $privateKey = null
+ ) {
$us = SemanticScuttle_Service_Factory::get('User');
$rand = rand();
@@ -109,13 +113,17 @@ class TestBase extends PHPUnit_Framework_TestCase
if ($password === null) {
$password = $rand;
}
+ if ($privateKey === true) {
+ $privateKey = $this->us->getNewPrivateKey();
+ }
$uid = $us->addUser(
$username,
$password,
- 'unittest-' . $rand . '@example.org'
+ 'unittest-' . $rand . '@example.org',
+ $privateKey
);
- return array($uid, $username, $password);
+ return array($uid, $username, $password, $privateKey);
}
@@ -148,4 +156,4 @@ class TestBase extends PHPUnit_Framework_TestCase
}
}
-?> \ No newline at end of file
+?>
diff --git a/tests/TestBaseApi.php b/tests/TestBaseApi.php
index 20574f3..1052ae7 100644
--- a/tests/TestBaseApi.php
+++ b/tests/TestBaseApi.php
@@ -24,7 +24,20 @@ require_once 'HTTP/Request2.php';
*/
class TestBaseApi extends TestBase
{
+ /**
+ * Created from the configured host and the $urlPart.
+ * Should be used as base for all generated URLs
+ *
+ * @var string
+ */
protected $url;
+
+ /**
+ * Part of the URL behind the configured host.
+ * Needs to be overwritten in each derived test case class.
+ *
+ * @var string
+ */
protected $urlPart = null;
/**
@@ -164,23 +177,25 @@ class TestBaseApi extends TestBase
*
* Useful for testing HTML pages or ajax URLs.
*
- * @param string $urlSuffix Suffix for the URL
- * @param mixed $auth If user authentication is needed (true/false)
- * or array with username and password
+ * @param string $urlSuffix Suffix for the URL
+ * @param mixed $auth If user authentication is needed (true/false)
+ * or array with username and password
+ * @param boolean $privateKey True if to add user with private key
*
* @return array(HTTP_Request2, integer) HTTP request object and user id
*
* @uses getRequest()
*/
- protected function getLoggedInRequest($urlSuffix = null, $auth = true)
- {
+ protected function getLoggedInRequest(
+ $urlSuffix = null, $auth = true, $privateKey = null
+ ) {
if (is_array($auth)) {
list($username, $password) = $auth;
} else {
$username = 'testuser';
$password = 'testpassword';
}
- $uid = $this->addUser($username, $password);
+ $uid = $this->addUser($username, $password, $privateKey);
$req = new HTTP_Request2(
$GLOBALS['unittestUrl'] . '/login.php?unittestMode=1',
@@ -234,7 +249,7 @@ class TestBaseApi extends TestBase
*/
protected function setUnittestConfig($arConfig)
{
- $str = '<' . "?php\r\n";
+ $str = '<' . "?php\n";
foreach ($arConfig as $name => $value) {
$str .= '$' . $name . ' = '
. var_export($value, true) . ";\n";
@@ -253,4 +268,4 @@ class TestBaseApi extends TestBase
);
}
}
-?> \ No newline at end of file
+?>
diff --git a/tests/UserTest.php b/tests/UserTest.php
index 2f57112..6cd6786 100644
--- a/tests/UserTest.php
+++ b/tests/UserTest.php
@@ -35,6 +35,157 @@ class UserTest extends TestBase
/**
+ * @covers SemanticScuttle_Service_User::addUser
+ */
+ public function testAddUserPrivateKey()
+ {
+ $name = substr(md5(uniqid()), 0, 6);
+ $pkey = 'my-privateKey';
+ $id = $this->us->addUser(
+ $name, uniqid(), 'foo@example.org', $pkey
+ );
+ $this->assertNotEquals(false, $id);
+ $this->assertInternalType('integer', $id);
+
+ $arUser = $this->us->getUserByPrivateKey($pkey);
+ $this->assertNotEquals(false, $arUser, 'user not found by private key');
+ $this->assertEquals($id, $arUser['uId'], 'wrong user loaded');
+ }
+
+
+ /**
+ * @covers SemanticScuttle_Service_User::updateUser
+ */
+ public function testUpdateUserFalseWhenIdNotNumeric()
+ {
+ $this->assertFalse(
+ $this->us->updateUser('foo', null, null, null, null, null)
+ );
+ }
+
+
+ /**
+ * @covers SemanticScuttle_Service_User::updateUser
+ */
+ public function testUpdateUserPrivateKeyNewKeyEnabled()
+ {
+ $pkey = 'testUpdateUserPrivateKeyNewKey12';
+ $uid = $this->addUser();
+
+ $this->assertTrue(
+ $this->us->updateUser(
+ $uid, 'password', 'name', 'test@example.org', '', '',
+ $pkey, true
+ )
+ );
+ $arUser = $this->us->getUser($uid);
+ $this->assertInternalType('array', $arUser);
+ $this->assertEquals($pkey, $arUser['privateKey']);
+ }
+
+
+ /**
+ * @covers SemanticScuttle_Service_User::updateUser
+ */
+ public function testUpdateUserPrivateKeyNewKeyDisabled()
+ {
+ $pkey = 'testUpdateUserPrivateKeyNewKeyDi';
+ $uid = $this->addUser();
+
+ $this->assertTrue(
+ $this->us->updateUser(
+ $uid, 'password', 'name', 'test@example.org', '', '',
+ $pkey, false
+ )
+ );
+ $arUser = $this->us->getUser($uid);
+ $this->assertInternalType('array', $arUser);
+ $this->assertEquals(
+ '-' . $pkey, $arUser['privateKey'],
+ 'private key did not get disabled'
+ );
+ }
+
+
+ /**
+ * Passing an empty string / NULL as key but enabling it
+ * should automatically create a new key.
+ *
+ * @covers SemanticScuttle_Service_User::updateUser
+ */
+ public function testUpdateUserPrivateKeyNoKeyEnabled()
+ {
+ $pkey = 'testUpdateUserPrivateKeyNoKeyEna';
+ $uid = $this->addUser();
+
+ $this->assertTrue(
+ $this->us->updateUser(
+ $uid, 'password', 'name', 'test@example.org', '', '',
+ null, true
+ )
+ );
+ $arUser = $this->us->getUser($uid);
+ $this->assertInternalType('array', $arUser);
+ $this->assertNotEquals(
+ '', $arUser['privateKey'], 'private key was not created'
+ );
+ }
+
+
+ /**
+ * Passing an empty string / NULL as key and disabling it
+ * should keep no key
+ *
+ * @covers SemanticScuttle_Service_User::updateUser
+ */
+ public function testUpdateUserPrivateKeyNoKeyDisabled()
+ {
+ $pkey = 'testUpdateUserPrivateKeyNoKeyDis';
+ $uid = $this->addUser();
+
+ $this->assertTrue(
+ $this->us->updateUser(
+ $uid, 'password', 'name', 'test@example.org', '', '',
+ null, false
+ )
+ );
+ $arUser = $this->us->getUser($uid);
+ $this->assertInternalType('array', $arUser);
+ $this->assertEquals(
+ '', $arUser['privateKey'], 'private key was set'
+ );
+ }
+
+
+ /**
+ * Passing an empty string / NULL as key and disabling it
+ * should keep no key
+ *
+ * @covers SemanticScuttle_Service_User::updateUser
+ */
+ public function testUpdateUserPrivateKeyExistingKeyEnabled()
+ {
+ $pkey = '12345678901234567890123456789012';
+ $uid = $this->addUser();
+
+ $this->assertTrue(
+ $this->us->updateUser(
+ $uid, 'password', 'name', 'test@example.org', '', '',
+ '-' . $pkey, true
+ )
+ );
+ $arUser = $this->us->getUser($uid);
+ $this->assertInternalType('array', $arUser);
+ $this->assertEquals(
+ $pkey, $arUser['privateKey'], 'private key was not enabled'
+ );
+ }
+
+ //FIXME: verify I cannot re-use private key of different user
+
+
+
+ /**
* Test that setting the current user ID is permanent.
* and that the current user array is the same ID
*
@@ -176,5 +327,185 @@ class UserTest extends TestBase
);
}
+
+ public function testGetUserByPrivateKeyEmptyKey()
+ {
+ $arUser = $this->us->getUserByPrivateKey(null);
+ $this->assertFalse($arUser);
+ }
+
+
+ public function testGetUserByPrivateKeyInvalid()
+ {
+ $arUser = $this->us->getUserByPrivateKey('foobar');
+ $this->assertFalse($arUser);
+
+ $arUser = $this->us->getUserByPrivateKey('%');
+ $this->assertFalse($arUser);
+ }
+
+
+ public function testGetUserByPrivateKeyValidKey()
+ {
+ $pkey = $this->us->getNewPrivateKey();
+ $uId = $this->addUser(null, null, $pkey);
+
+ $arUser = $this->us->getUserByPrivateKey($pkey);
+ $this->assertInternalType('array', $arUser);
+ $this->assertArrayHasKey('uId', $arUser);
+ $this->assertArrayHasKey('username', $arUser);
+
+ $this->assertEquals($uId, $arUser['uId']);
+ }
+
+
+ /**
+ * @covers SemanticScuttle_Service_User::privateKeyExists
+ */
+ public function testPrivateKeyExistsEmpty()
+ {
+ $this->assertFalse($this->us->privateKeyExists(null));
+ $this->assertFalse($this->us->privateKeyExists(''));
+ }
+
+
+ /**
+ * @covers SemanticScuttle_Service_User::privateKeyExists
+ */
+ public function testPrivateKeyExistsInvalid()
+ {
+ $this->assertFalse($this->us->privateKeyExists('-1'));
+ }
+
+
+ /**
+ * @covers SemanticScuttle_Service_User::privateKeyExists
+ */
+ public function testPrivateKeyExists()
+ {
+ $randKey = $this->us->getNewPrivateKey();
+ $this->assertFalse($this->us->privateKeyExists($randKey));
+ $uid = $this->addUser(null, null, $randKey);
+
+ $this->us->setCurrentUserId($uid);
+ $this->assertEquals($uid, $this->us->getCurrentUserId());
+
+ $this->assertTrue($this->us->privateKeyExists($randKey));
+ }
+
+
+ /**
+ * @covers SemanticScuttle_Service_User::isPrivateKeyValid
+ */
+ public function testIsPrivateKeyValid()
+ {
+ $this->assertFalse(
+ $this->us->isPrivateKeyValid(null),
+ 'NULL is an invalid private key'
+ );
+
+ $randKey = $this->us->getNewPrivateKey();
+ $this->assertTrue(
+ $this->us->isPrivateKeyValid($randKey),
+ 'generated key should be valid'
+ );
+
+ $randKey2 = '-'.$this->us->getNewPrivateKey();
+ $this->assertFalse(
+ $this->us->isPrivateKeyValid($randKey2),
+ 'disabled privateKey should return false'
+ );
+ }
+
+
+ public function testLoginPrivateKeyInvalid()
+ {
+ /* normal user with enabled privateKey */
+ $randKey = $this->us->getNewPrivateKey();
+ $uid1 = $this->addUser('testusername', 'passw0rd', $randKey);
+ /* user that has disabled privateKey */
+ $randKey2 = '-'.$this->us->getNewPrivateKey();
+ $uid2 = $this->addUser('seconduser', 'passw0RD', $randKey2);
+
+ /* test invalid private key */
+ $this->assertFalse(
+ $this->us->loginPrivateKey('02848248084082408240824802408248')
+ );
+ }
+
+
+ public function testLoginPrivateKeyValidEnabledKey()
+ {
+ /* normal user with enabled privateKey */
+ $randKey = $this->us->getNewPrivateKey();
+ $uid1 = $this->addUser('testusername', 'passw0rd', $randKey);
+ /* user that has disabled privateKey */
+ $randKey2 = '-'.$this->us->getNewPrivateKey();
+ $uid2 = $this->addUser('seconduser', 'passw0RD', $randKey2);
+
+
+ /* test valid credentials with private key enabled */
+ $this->assertTrue(
+ $this->us->loginPrivateKey($randKey)
+ );
+ }
+
+
+ public function testLoginPrivateKeyInvalidEnabledKey()
+ {
+ /* normal user with enabled privateKey */
+ $randKey = $this->us->getNewPrivateKey();
+ $uid1 = $this->addUser('testusername', 'passw0rd', $randKey);
+ /* user that has disabled privateKey */
+ $randKey2 = '-'.$this->us->getNewPrivateKey();
+ $uid2 = $this->addUser('seconduser', 'passw0RD', $randKey2);
+
+
+ /* test valid credentials with private key enabled but invalid key */
+ $this->assertFalse(
+ $this->us->loginPrivateKey('123')
+ );
+ }
+
+
+ public function testLoginPrivateKeyValidDisabledKey()
+ {
+ /* normal user with enabled privateKey */
+ $randKey = $this->us->getNewPrivateKey();
+ $uid1 = $this->addUser('testusername', 'passw0rd', $randKey);
+ /* user that has disabled privateKey */
+ $randKey2 = '-'.$this->us->getNewPrivateKey();
+ $uid2 = $this->addUser('seconduser', 'passw0RD', $randKey2);
+
+ /* confirm user exists so future fails should be due to randkey */
+ $this->assertTrue(
+ $this->us->login('seconduser', 'passw0RD', false)
+ );
+
+ /* test valid credentials with private key disabled */
+ $this->assertFalse(
+ $this->us->loginPrivateKey($randKey2)
+ );
+ }
+
+
+ public function testLoginPrivateKeyInvalidDisabled()
+ {
+ /* normal user with enabled privateKey */
+ $randKey = $this->us->getNewPrivateKey();
+ $uid1 = $this->addUser('testusername', 'passw0rd', $randKey);
+ /* user that has disabled privateKey */
+ $randKey2 = '-'.$this->us->getNewPrivateKey();
+ $uid2 = $this->addUser('seconduser', 'passw0RD', $randKey2);
+
+ /* test valid credentials with private key disabled and invalid key */
+ $this->assertFalse(
+ $this->us->loginPrivateKey('-1')
+ );
+ $this->assertFalse(
+ $this->us->loginPrivateKey(null)
+ );
+ }
+
}
-?> \ No newline at end of file
+?>
diff --git a/tests/www/bookmarksTest.php b/tests/www/bookmarksTest.php
index df360cc..ae82118 100755
--- a/tests/www/bookmarksTest.php
+++ b/tests/www/bookmarksTest.php
@@ -4,7 +4,7 @@ require_once 'HTTP/Request2.php';
class www_bookmarksTest extends TestBaseApi
{
- protected $urlPart = 'api/posts/add';
+ protected $urlPart = 'bookmarks.php';
/**
* Test that the default privacy setting is selected in the Privacy
@@ -16,23 +16,11 @@ class www_bookmarksTest extends TestBaseApi
$this->setUnittestConfig(
array('defaults' => array('privacy' => 2))
);
- list($req, $uId) = $this->getLoggedInRequest();
- $cookies = $req->getCookieJar();
- $req->setMethod(HTTP_Request2::METHOD_POST);
- $req->addPostParameter('url', 'http://www.example.org/testdefaultprivacyposts_bookmarksget');
- $req->addPostParameter('description', 'Test bookmark 1 for default privacy.');
- $req->addPostParameter('status', '0');
- $req->send();
- $bms = $this->bs->getBookmarks(0, null, $uId);
- $this->assertEquals(1, count($bms['bookmarks']));
+ list($req, $uId) = $this->getLoggedInRequest();
$user = $this->us->getUser($uId);
- $reqUrl = $GLOBALS['unittestUrl'] . 'bookmarks.php/' . $user['username'] . '?action=get' . '&unittestMode=1';
-
- list($req, $uId) = $this->getAuthRequest('?unittestMode=1');
$req->setMethod(HTTP_Request2::METHOD_POST);
- $req->setUrl($reqUrl);
- $req->setCookieJar($cookies);
+ $req->setUrl($this->getTestUrl('/' . $user['username'] . '?action=get'));
$req->addPostParameter('submitted', '1');
$response = $req->send();
$response_body = $response->getBody();
@@ -41,12 +29,15 @@ class www_bookmarksTest extends TestBaseApi
$ns = $x->getDocNamespaces();
$x->registerXPathNamespace('ns', reset($ns));
- $elements = $x->xpath('//ns:select[@name="status"]/ns:option[@selected="selected"]');
+ $elements = $x->xpath(
+ '//ns:select[@name="status"]/ns:option[@selected="selected"]'
+ );
$this->assertEquals(1, count($elements), 'No selected status option found');
$this->assertEquals(2, (string)$elements[0]['value']);
}//end testDefaultPrivacyBookmarksAddMissingTitleMissingPrivacy
+
/**
* Test that the default privacy setting is selected in the Privacy
* drop-down list when a new bookmark is being created.
@@ -56,13 +47,10 @@ class www_bookmarksTest extends TestBaseApi
$this->setUnittestConfig(
array('defaults' => array('privacy' => 1))
);
- list($req, $uId) = $this->getLoggedInRequest('?unittestMode=1');
+ list($req, $uId) = $this->getLoggedInRequest();
$user = $this->us->getUser($uId);
- $reqUrl = $GLOBALS['unittestUrl'] . 'bookmarks.php/'
- . $user['username'] . '?action=add' . '&unittestMode=1';
- $req->setUrl($reqUrl);
- $req->setMethod(HTTP_Request2::METHOD_GET);
+ $req->setUrl($this->getTestUrl('/' . $user['username'] . '?action=add'));
$response = $req->send();
$response_body = $response->getBody();
$this->assertNotEquals('', $response_body, 'Response is empty');
@@ -71,10 +59,70 @@ class www_bookmarksTest extends TestBaseApi
$ns = $x->getDocNamespaces();
$x->registerXPathNamespace('ns', reset($ns));
- $elements = $x->xpath('//ns:select[@name="status"]/ns:option[@selected="selected"]');
+ $elements = $x->xpath(
+ '//ns:select[@name="status"]/ns:option[@selected="selected"]'
+ );
$this->assertEquals(1, count($elements), 'No selected status option found');
$this->assertEquals(1, (string)$elements[0]['value']);
}//end testDefaultPrivacyBookmarksAdd
+
+
+ /**
+ * Test that the private RSS link exists when a user
+ * has a private key and is enabled
+ */
+ public function testVerifyPrivateRSSLinkExists()
+ {
+ list($req, $uId) = $this->getLoggedInRequest('?unittestMode=1', true, true);
+
+ $user = $this->us->getUser($uId);
+ $req->setUrl($this->getTestUrl('/' . $user['username']));
+ $response = $req->send();
+ $response_body = $response->getBody();
+ $this->assertNotEquals('', $response_body, 'Response is empty');
+
+ $x = simplexml_load_string($response_body);
+ $ns = $x->getDocNamespaces();
+ $x->registerXPathNamespace('ns', reset($ns));
+
+ $elements = $x->xpath(
+ '//ns:link[@rel="alternate" and @type="application/rss+xml"]'
+ );
+ $this->assertEquals(
+ 2, count($elements), 'Number of Links in Head not correct'
+ );
+ $this->assertContains('privateKey=', (string)$elements[1]['href']);
+ }//end testVerifyPrivateRSSLinkExists
+
+
+
+ /**
+ * Test that the private RSS link doesn't exists when a user
+ * does not have a private key or is not enabled
+ */
+ public function testVerifyPrivateRSSLinkDoesNotExist()
+ {
+ list($req, $uId) = $this->getLoggedInRequest('?unittestMode=1', true);
+
+ $user = $this->us->getUser($uId);
+ $req->setUrl($this->getTestUrl('/' . $user['username']));
+ $response = $req->send();
+ $response_body = $response->getBody();
+ $this->assertNotEquals('', $response_body, 'Response is empty');
+
+ $x = simplexml_load_string($response_body);
+ $ns = $x->getDocNamespaces();
+ $x->registerXPathNamespace('ns', reset($ns));
+
+ $elements = $x->xpath(
+ '//ns:link[@rel="alternate" and @type="application/rss+xml"]'
+ );
+ $this->assertEquals(
+ 1, count($elements), 'Number of Links in Head not correct'
+ );
+ $this->assertNotContains('privateKey=', (string)$elements[0]['href']);
+ }//end testVerifyPrivateRSSLinkDoesNotExist
+
}//end class www_bookmarksTest
?>
diff --git a/tests/www/indexTest.php b/tests/www/indexTest.php
new file mode 100644
index 0000000..503fd1f
--- /dev/null
+++ b/tests/www/indexTest.php
@@ -0,0 +1,58 @@
+<?php
+require_once dirname(__FILE__) . '/../prepare.php';
+require_once 'HTTP/Request2.php';
+
+class www_indexTest extends TestBaseApi
+{
+ protected $urlPart = '';
+
+ /**
+ * Test that the private rss feed exists when user is setup
+ * with a private key and is enabled
+ */
+ public function testVerifyPrivateRSSLinkExists()
+ {
+ list($req, $uId) = $this->getLoggedInRequest('?unittestMode=1', true, true);
+
+ $user = $this->us->getUser($uId);
+ $response = $req->send();
+ $response_body = $response->getBody();
+
+ $this->assertNotEquals('', $response_body, 'Response is empty');
+
+ $x = simplexml_load_string($response_body);
+ $ns = $x->getDocNamespaces();
+ $x->registerXPathNamespace('ns', reset($ns));
+
+ $elements = $x->xpath('//ns:link[@rel="alternate" and @type="application/rss+xml"]');
+ $this->assertEquals(2, count($elements), 'Number of Links in Head not correct');
+ $this->assertContains('privateKey=', (string)$elements[1]['href']);
+ }//end testVerifyPrivateRSSLinkExists
+
+
+
+ /**
+ * Test that the private RSS link doesn't exists when a user
+ * does not have a private key, or the private key is not enabled
+ */
+ public function testVerifyPrivateRSSLinkDoesNotExist()
+ {
+ list($req, $uId) = $this->getLoggedInRequest('?unittestMode=1', true);
+
+ $user = $this->us->getUser($uId);
+ $response = $req->send();
+ $response_body = $response->getBody();
+ $this->assertNotEquals('', $response_body, 'Response is empty');
+
+ $x = simplexml_load_string($response_body);
+ $ns = $x->getDocNamespaces();
+ $x->registerXPathNamespace('ns', reset($ns));
+
+ $elements = $x->xpath('//ns:link[@rel="alternate" and @type="application/rss+xml"]');
+ $this->assertEquals(1, count($elements), 'Number of Links in Head not correct');
+ $this->assertNotContains('privateKey=', (string)$elements[0]['href']);
+ }//end testVerifyPrivateRSSLinkDoesNotExist
+
+
+}//end class www_bookmarksTest
+?>
diff --git a/tests/www/rssTest.php b/tests/www/rssTest.php
new file mode 100644
index 0000000..71d0198
--- /dev/null
+++ b/tests/www/rssTest.php
@@ -0,0 +1,151 @@
+<?php
+require_once dirname(__FILE__) . '/../prepare.php';
+require_once 'HTTP/Request2.php';
+
+class www_rssTest extends TestBaseApi
+{
+ protected $urlPart = 'rss.php';
+
+
+ /**
+ * Verifies that the given number of feed items exist in the feed
+ * XML tree.
+ *
+ * @var SimpleXMLElement $simpleXml RSS feed root element
+ * @var integer $nCount Number of expected feed items
+ * @var string $msg Error message
+ */
+ protected function assertItemCount(
+ SimpleXMLElement $simpleXml, $nCount, $msg = null
+ ) {
+ $this->assertEquals($nCount, count($simpleXml->channel->item), $msg);
+ }
+
+
+
+
+ /**
+ * A private bookmark should not show up in the global rss feed if the
+ * user is not logged in nor passes the private key
+ */
+ public function testAllPrivateBookmarkNotLoggedIn()
+ {
+ list($uId, $username) = $this->addUserData();
+ $this->addBookmark(
+ $uId, null, SemanticScuttle_Model_Bookmark::SPRIVATE
+ );
+
+ $req = $this->getRequest();
+ $response_body = $req->send()->getBody();
+
+ $rss = simplexml_load_string($response_body);
+ $this->assertItemCount($rss, 0, 'I see a private bookmark');
+ }
+
+
+
+ /**
+ * A private bookmark should not show up in the user's rss feed if the
+ * user is not logged in nor passes the private key
+ */
+ public function testUserPrivateBookmarkNotLoggedIn()
+ {
+ list($uId, $username) = $this->addUserData();
+ $this->addBookmark(
+ $uId, null, SemanticScuttle_Model_Bookmark::SPRIVATE
+ );
+
+ $req = $this->getRequest('/' . $username);
+ $response_body = $req->send()->getBody();
+
+ $rss = simplexml_load_string($response_body);
+ $this->assertItemCount($rss, 0, 'I see a private bookmark');
+ }
+
+
+
+
+ /**
+ * Test the global feed by passing the private key
+ */
+ public function testAllPrivateBookmarkWithPrivateKey()
+ {
+ list($uId, $username, $password, $privateKey) = $this->addUserData(
+ null, null, true
+ );
+ $this->addBookmark(
+ $uId, null, SemanticScuttle_Model_Bookmark::SPRIVATE,
+ null, 'private bookmark'
+ );
+
+ $req = $this->getRequest('?privateKey=' . $privateKey);
+ $response_body = $req->send()->getBody();
+
+ $rss = simplexml_load_string($response_body);
+ $this->assertItemCount($rss, 1, 'I miss the private bookmark');
+ $this->assertEquals(
+ 'private bookmark', (string)$rss->channel->item[0]->title
+ );
+ }
+
+
+
+ /**
+ * Test the user feed by passing the private key
+ */
+ public function testUserPrivateBookmarkWithPrivateKey()
+ {
+ list($uId, $username, $password, $privateKey) = $this->addUserData(
+ null, null, true
+ );
+ $this->addBookmark(
+ $uId, null, SemanticScuttle_Model_Bookmark::SPRIVATE,
+ null, 'private bookmark'
+ );
+
+ $req = $this->getRequest('/' . $username . '?privateKey=' . $privateKey);
+ $response_body = $req->send()->getBody();
+
+ $rss = simplexml_load_string($response_body);
+ $this->assertItemCount($rss, 1, 'I miss the private bookmark');
+ $this->assertEquals(
+ 'private bookmark', (string)$rss->channel->item[0]->title
+ );
+ }
+
+
+
+ /**
+ * Verify that fetching the feed with a private key
+ * does not keep you logged in
+ */
+ public function testUserPrivateKeyDoesNotKeepLoggedYouIn()
+ {
+ list($uId, $username, $password, $privateKey) = $this->addUserData(
+ null, null, true
+ );
+ $this->addBookmark(
+ $uId, null, SemanticScuttle_Model_Bookmark::SPRIVATE,
+ null, 'private bookmark'
+ );
+
+ $req = $this->getRequest('/' . $username . '?privateKey=' . $privateKey);
+ $cookies = $req->setCookieJar()->getCookieJar();
+ $response_body = $req->send()->getBody();
+
+ $rss = simplexml_load_string($response_body);
+ $items = $rss->channel->item;
+
+ $this->assertEquals(1, count($items), 'I miss the private bookmark');
+ $this->assertEquals('private bookmark', (string)$items[0]->title);
+
+ //request the feed again, with the same cookies
+ $req = $this->getRequest('/' . $username);
+ $req->setCookieJar($cookies);
+ $response_body = $req->send()->getBody();
+ $rss = simplexml_load_string($response_body);
+ $this->assertItemCount($rss, 0, 'I still see the private bookmark');
+ }
+
+}//end class www_rssTest
+?>
diff --git a/tests/www/searchTest.php b/tests/www/searchTest.php
index 5dce69d..89af32d 100644
--- a/tests/www/searchTest.php
+++ b/tests/www/searchTest.php
@@ -1,4 +1,6 @@
<?php
+require_once dirname(__FILE__) . '/../prepare.php';
+require_once 'HTTP/Request2.php';
class www_SearchTest extends TestBaseApi
{
@@ -65,4 +67,4 @@ class www_SearchTest extends TestBaseApi
}
-?> \ No newline at end of file
+?>
diff --git a/www/ajaxGetNewPrivateKey.php b/www/ajaxGetNewPrivateKey.php
new file mode 100644
index 0000000..eacebd8
--- /dev/null
+++ b/www/ajaxGetNewPrivateKey.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Ajax script to retrieve new Private Key
+ *
+ * PHP version 5.
+ *
+ * @category Bookmarking
+ * @package SemanticScuttle
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @author Mark Pemberton <mpemberton5@gmail.com>
+ * @license AGPL http://www.gnu.org/licenses/agpl.html
+ * @link http://sourceforge.net/projects/semanticscuttle
+ */
+
+header("Last-Modified: ". gmdate("D, d M Y H:i:s") ." GMT");
+header("Cache-Control: no-cache, must-revalidate");
+
+$httpContentType = 'text/xml';
+require_once 'www-header.php';
+
+$us = SemanticScuttle_Service_Factory::get('User');
+
+/* Managing all possible inputs */
+isset($_GET['url']) ? define('GET_URL', $_GET['url']): define('GET_URL', '');
+
+echo '<?xml version="1.0" encoding="utf-8"?>';
+?>
+<response>
+<method>
+getNewPrivateKey
+</method>
+<result>
+<?php echo $us->getNewPrivateKey(); ?>
+</result>
+</response>
diff --git a/www/bookmarks.php b/www/bookmarks.php
index efc1680..72c063e 100644
--- a/www/bookmarks.php
+++ b/www/bookmarks.php
@@ -229,12 +229,14 @@ if ($templatename == 'editbookmark.tpl') {
$tplVars['sidebar_blocks'] = array('watchstatus');
if (!$cat) { //user page without tags
+ $rssTitle = "My Bookmarks";
$cat = NULL;
$tplVars['currenttag'] = NULL;
//$tplVars['sidebar_blocks'][] = 'menu2';
$tplVars['sidebar_blocks'][] = 'linked';
$tplVars['sidebar_blocks'][] = 'popular';
} else { //pages with tags
+ $rssTitle = "Tags" . $catTitle;
$rssCat = '/'. filter($cat, 'url');
$tplVars['currenttag'] = $cat;
$tplVars['sidebar_blocks'][] = 'tagactions';
@@ -264,9 +266,32 @@ if ($templatename == 'editbookmark.tpl') {
// Set template vars
$tplVars['rsschannels'] = array(
- array(filter($sitename .': '. $pagetitle), createURL('rss', filter($user, 'url') . $rssCat.'?sort='.getSortOrder()))
+ array(
+ sprintf(T_('%s: %s'), $sitename, $rssTitle),
+ createURL('rss', filter($user, 'url'))
+ . $rssCat . '?sort='.getSortOrder()
+ )
);
+ if ($userservice->isLoggedOn()) {
+ $currentUsername = $currentUser->getUsername();
+ if ($userservice->isPrivateKeyValid($currentUser->getPrivateKey())) {
+ array_push(
+ $tplVars['rsschannels'],
+ array(
+ sprintf(
+ T_('%s: %s (+private %s)'),
+ $sitename, $rssTitle, $currentUsername
+ ),
+ createURL('rss', filter($currentUsername, 'url'))
+ . $rssCat
+ . '?sort=' . getSortOrder()
+ . '&privateKey=' . $currentUser->getPrivateKey()
+ )
+ );
+ }
+ }
+
$tplVars['page'] = $page;
$tplVars['start'] = $start;
$tplVars['bookmarkCount'] = $start + 1;
diff --git a/www/index.php b/www/index.php
index f6704ae..7fbb84c 100644
--- a/www/index.php
+++ b/www/index.php
@@ -42,9 +42,30 @@ if (GET_ACTION == "logout") {
// Header variables
$tplVars['loadjs'] = true;
$tplVars['rsschannels'] = array(
-array(sprintf(T_('%s: Recent bookmarks'), $sitename), createURL('rss').'?sort='.getSortOrder())
+ array(
+ sprintf(T_('%s: Recent bookmarks'), $sitename),
+ createURL('rss') . '?sort=' . getSortOrder()
+ )
);
+if ($userservice->isLoggedOn()) {
+ if ($userservice->isPrivateKeyValid($currentUser->getPrivateKey())) {
+ $currentUsername = $currentUser->getUsername();
+ array_push(
+ $tplVars['rsschannels'],
+ array(
+ sprintf(
+ T_('%s: Recent bookmarks (+private %s)'),
+ $sitename, $currentUsername
+ ),
+ createURL('rss')
+ . '?sort=' . getSortOrder()
+ . '&privateKey=' . $currentUser->getPrivateKey()
+ )
+ );
+ }
+}
+
if ($usecache) {
// Generate hash for caching on
$hashtext = $_SERVER['REQUEST_URI'];
diff --git a/www/js/jstree-1.0-rc2/MultiComboBox.js b/www/js/jstree-1.0-rc2/MultiComboBox.js
deleted file mode 100644
index b263c8b..0000000
--- a/www/js/jstree-1.0-rc2/MultiComboBox.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- Copyright (c) 2004-2008, The Dojo Foundation All Rights Reserved.
- Available via Academic Free License >= 2.1 OR the modified BSD license.
- see: http://dojotoolkit.org/license for details
-*/
-
-/* SemanticScuttle: This script is a light modification of dojox.form.MultiComboBox
-This fork allows specific use until DOJO 1.2.3 in Google CDN. */
-
-
-
-if(!dojo._hasResource["js.MultiComboBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
-dojo._hasResource["js.MultiComboBox"] = true;
-dojo.provide("js.MultiComboBox");
-dojo.experimental("js.MultiComboBox");
-dojo.require("dijit.form.ComboBox");
-dojo.require("dijit.form.ValidationTextBox");
-
-dojo.declare("js.MultiComboBox",
- [dijit.form.ValidationTextBox, dijit.form.ComboBoxMixin],{
- //
- // summary: A ComboBox that accpets multiple inputs on a single line?
- //
- // delimiter: String
- // The character to use to separate items in the ComboBox input
- delimiter: ",",
- _previousMatches: false,
-
- _setValueAttr: function(value){
- if (this.delimiter && value.length != 0){
- value = value+this.delimiter+" ";
- arguments[0] = this._addPreviousMatches(value);
- }
- this.inherited(arguments);
- },
-
- _addPreviousMatches: function(/* String */text){
- if(this._previousMatches){
- if(!text.match(new RegExp("^"+this._previousMatches))){
- text = this._previousMatches+text;
- }
- }
- text = this._cleanupDelimiters(text); // SScuttle: this line was moved
- return text; // String
- },
-
- _cleanupDelimiters: function(/* String */text){
- if(this.delimiter){
- text = text.replace(new RegExp(" +"), " ");
- text = text.replace(new RegExp("^ *"+this.delimiter+"* *"), "");
- text = text.replace(new RegExp(this.delimiter+" *"+this.delimiter), this.delimiter);
- }
- return text;
- },
-
- _autoCompleteText: function(/* String */text){
- arguments[0] = this._addPreviousMatches(text);
- this.inherited(arguments);
- },
-
- _startSearch: function(/* String */text){
- text = this._cleanupDelimiters(text);
- var re = new RegExp("^.*"+this.delimiter+" *");
-
- if((this._previousMatches = text.match(re))){
- arguments[0] = text.replace(re, "");
- }
- this.inherited(arguments);
- }
-});
-
-} \ No newline at end of file
diff --git a/www/jsScuttle.php b/www/jsScuttle.php
index 5e5f31b..de97fd2 100644
--- a/www/jsScuttle.php
+++ b/www/jsScuttle.php
@@ -90,6 +90,24 @@ function useAddress(ele) {
}
}
+/**
+ * Makes an ajax call to PHP script to generate an new Private Key
+ *
+ * @param input Calling object
+ * @param response Response object that returned value is placed
+ *
+ * @return boolean Returns false to halt execution after call
+ */
+function getNewPrivateKey(input, response){
+ var pk = document.getElementById('pPrivateKey');
+ if (response != null) {
+ pk.value = response.trim();
+ } else {
+ loadXMLDocProc('<?php echo ROOT; ?>ajaxGetNewPrivateKey.php');
+ }
+ return false;
+}
+
function getTitle(input, response){
var title = document.getElementById('titleField');
if (title.value == '') {
diff --git a/www/profile.php b/www/profile.php
index ccdb7a8..63f4da8 100644
--- a/www/profile.php
+++ b/www/profile.php
@@ -23,12 +23,16 @@ require_once 'www-header.php';
/* Service creation: only useful services are created */
// No specific services
+$tplVars['loadjs'] = true;
/* Managing all possible inputs */
+isset($_POST['submittedPK']) ? define('POST_SUBMITTEDPK', $_POST['submittedPK']): define('POST_SUBMITTEDPK', '');
isset($_POST['submitted']) ? define('POST_SUBMITTED', $_POST['submitted']): define('POST_SUBMITTED', '');
isset($_POST['pPass']) ? define('POST_PASS', $_POST['pPass']): define('POST_PASS', '');
isset($_POST['pPassConf']) ? define('POST_PASSCONF', $_POST['pPassConf']): define('POST_PASSCONF', '');
isset($_POST['pName']) ? define('POST_NAME', $_POST['pName']): define('POST_NAME', '');
+isset($_POST['pPrivateKey']) ? define('POST_PRIVATEKEY', $_POST['pPrivateKey']): define('POST_PRIVATEKEY', '');
+isset($_POST['pEnablePrivateKey']) ? define('POST_ENABLEPRIVATEKEY', $_POST['pEnablePrivateKey']): define('POST_ENABLEPRIVATEKEY', '');
isset($_POST['pMail']) ? define('POST_MAIL', $_POST['pMail']): define('POST_MAIL', '');
isset($_POST['pPage']) ? define('POST_PAGE', $_POST['pPage']): define('POST_PAGE', '');
isset($_POST['pDesc']) ? define('POST_DESC', $_POST['pDesc']): define('POST_DESC', '');
@@ -61,10 +65,19 @@ if ($user) {
exit();
}
+$tplVars['privateKeyIsEnabled'] = '';
if ($userservice->isLoggedOn() && $user == $currentUser->getUsername()) {
- $title = T_('My Profile');
+ $title = T_('My Profile');
+ $tplVars['privateKey'] = $currentUser->getPrivateKey(true);
+
+ if ($userservice->isPrivateKeyValid($currentUser->getPrivateKey())) {
+ $tplVars['privateKeyIsEnabled'] = 'checked="checked"';
+ } else {
+ $tplVars['privateKeyIsEnabled'] = '';
+ }
} else {
- $title = T_('Profile') .': '. $user;
+ $title = T_('Profile') .': '. $user;
+ $tplVars['privateKey'] = '';
}
$tplVars['pagetitle'] = $title;
$tplVars['subtitle'] = $title;
@@ -72,11 +85,19 @@ $tplVars['subtitle'] = $title;
$tplVars['user'] = $user;
$tplVars['userid'] = $userid;
+/* Update Private Key */
+if (POST_SUBMITTEDPK!='' && $currentUser->getId() == $userid) {
+ $userinfo = $userservice->getObjectUserByUsername($user);
+ $tplVars['privateKey'] = $userservice->getNewPrivateKey();
+}
+
if (POST_SUBMITTED!='' && $currentUser->getId() == $userid) {
$error = false;
$detPass = trim(POST_PASS);
$detPassConf = trim(POST_PASSCONF);
$detName = trim(POST_NAME);
+ $detPrivateKey = trim(POST_PRIVATEKEY);
+ $detEnablePrivateKey = trim(POST_ENABLEPRIVATEKEY);
$detMail = trim(POST_MAIL);
$detPage = trim(POST_PAGE);
$detDesc = filter(POST_DESC);
@@ -102,13 +123,19 @@ if (POST_SUBMITTED!='' && $currentUser->getId() == $userid) {
$tplVars['error'] = T_('E-mail address is not valid.');
}
if (!$error) {
- if (!$userservice->updateUser($userid, $detPass, $detName, $detMail, $detPage, $detDesc)) {
+ if (!$userservice->updateUser($userid, $detPass, $detName, $detMail, $detPage, $detDesc, $detPrivateKey, $detEnablePrivateKey)) {
$tplVars['error'] = T_('An error occurred while saving your changes.');
} else {
$tplVars['msg'] = T_('Changes saved.');
}
}
$userinfo = $userservice->getObjectUserByUsername($user);
+ $tplVars['privateKey'] = $userinfo->getPrivateKey(true);
+ if ($userservice->isPrivateKeyValid($userinfo->getPrivateKey())) {
+ $tplVars['privateKeyIsEnabled'] = 'checked="checked"';
+ } else {
+ $tplVars['privateKeyIsEnabled'] = '';
+ }
}
if (!$userservice->isLoggedOn() || $currentUser->getId() != $userid) {
diff --git a/www/rss.php b/www/rss.php
index 50240e5..d888726 100644
--- a/www/rss.php
+++ b/www/rss.php
@@ -64,7 +64,12 @@ if (!isset($rssEntries) || $rssEntries <= 0) {
$rssEntries = $maxRssEntries;
}
+$privateKey = null;
+if (isset($_GET['privateKey'])) {
+ $privateKey = $_GET['privateKey'];
+}
+$userid = null;
$watchlist = null;
$pagetitle = '';
if ($user && $user != 'all') {
@@ -78,8 +83,22 @@ if ($user && $user != 'all') {
} else {
if ($userinfo = $userservice->getUserByUsername($user)) {
$userid =& $userinfo[$userservice->getFieldName('primary')];
+ /* if user is not logged in and has valid privateKey */
+ if (!$userservice->isLoggedOn()) {
+ if ($privateKey != null) {
+ if (!$userservice->loginPrivateKey($privateKey)) {
+ $tplVars['error'] = sprintf(T_('Failed to Autenticate User with username %s using private key'), $user);
+ header('Content-type: text/html; charset=utf-8');
+ $templateservice->loadTemplate('error.404.tpl', $tplVars);
+ //throw a 404 error
+ exit();
+ }
+ }
+ }
+
} else {
$tplVars['error'] = sprintf(T_('User with username %s was not found'), $user);
+ header('Content-type: text/html; charset=utf-8');
$templateservice->loadTemplate('error.404.tpl', $tplVars);
//throw a 404 error
exit();
@@ -87,7 +106,17 @@ if ($user && $user != 'all') {
}
$pagetitle .= ": ". $user;
} else {
- $userid = null;
+ if ($privateKey != null) {
+ if (!$userservice->loginPrivateKey($privateKey)) {
+ $tplVars['error'] = sprintf(T_('Failed to Autenticate User with username %s using private key'), $user);
+ header('Content-type: text/html; charset=utf-8');
+ $templateservice->loadTemplate('error.404.tpl', $tplVars);
+ //throw a 404 error
+ exit();
+ }
+ } else {
+ $userid = null;
+ }
}
if ($cat) {
@@ -100,7 +129,8 @@ $tplVars['feeddescription'] = sprintf(T_('Recent bookmarks posted to %s'), $GLOB
$bookmarks = $bookmarkservice->getBookmarks(
0, $rssEntries, $userid, $cat,
- null, getSortOrder(), $watchlist
+ null, getSortOrder(), $watchlist,
+ null, null, null
);
$bookmarks_tmp = filter($bookmarks['bookmarks']);
diff --git a/www/tags.php b/www/tags.php
index a4e6555..127f6c5 100644
--- a/www/tags.php
+++ b/www/tags.php
@@ -67,9 +67,31 @@ if ($usecache) {
$tplVars['pagetitle'] = T_('Tags') .': '. $cat;
$tplVars['loadjs'] = true;
$tplVars['rsschannels'] = array(
-array(filter($sitename .': '. $pagetitle), createURL('rss', 'all/'. filter($cat, 'url')).'?sort='.getSortOrder())
+ array(
+ sprintf(T_('%s: tagged with "%s"'), $sitename, $cat),
+ createURL('rss', 'all/' . filter($cat, 'url'))
+ . '?sort='.getSortOrder()
+ )
);
+if ($userservice->isLoggedOn()) {
+ if ($userservice->isPrivateKeyValid($currentUser->getPrivateKey())) {
+ $currentUsername = $currentUser->getUsername();
+ array_push(
+ $tplVars['rsschannels'],
+ array(
+ sprintf(
+ T_('%s: tagged with "%s" (+private %s)'),
+ $sitename, $cat, $currentUsername
+ ),
+ createURL('rss', filter($currentUsername, 'url'))
+ . '?sort=' . getSortOrder()
+ . '&privateKey=' . $currentUser->getPrivateKey()
+ )
+ );
+ }
+}
+
// Pagination
$perpage = getPerPageCount($currentUser);
if (intval(GET_PAGE) > 1) {