Commit 53de0f9c authored by Liang Ding's avatar Liang Ding

Merge pull request #229 from b3log/0.6.0

Released 0.6.0
parents 0f951c50 706c607c
......@@ -6,3 +6,5 @@
/war/mysql/target/
/war/h2/target/
/war/src/main/webapp/WEB-INF/lib/
/.idea/
/target/
\ No newline at end of file
......@@ -5,6 +5,51 @@
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<h2>Release 0.6.0 - Apr 26, 2013</h2>
<ul>
<li><a href="https://github.com/b3log/b3log-solo/issues/199">199 社区文章更新接口</a>&nbsp;<span style='background: #02e10c !important;color:#FFFFFF !important;padding: 1px 4px;'>feature</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/203">203 用户注册,实现多用户博客</a>&nbsp;<span style='background: #02e10c !important;color:#FFFFFF !important;padding: 1px 4px;'>feature</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/226">226 加入字典存储 option</a>&nbsp;<span style='background: #e102d8 !important;color:#FFFFFF !important;padding: 1px 4px;'>development</span>&nbsp;<span style='background: #02e10c !important;color:#FFFFFF !important;padding: 1px 4px;'>feature</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/198">198 删除文章出错</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/205">205 禁用缓存后文章浏览计数不变</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/214">214 Zoundry Raven 发布问题</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/144">144 KindEditor 上传问题</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/193">193 登录后再访问登录页将跳转后台</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/194">194 删除操作提示改进</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/195">195 去除草稿夹浏览按钮</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/196">196 清除缓存丢失访问统计</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/202">202 自定义 Feed 文章数</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/210">210 升级至 GAE 1.7.7</a>&nbsp;<span style='background: #e102d8 !important;color:#FFFFFF !important;padding: 1px 4px;'>development</span></li>
</ul>
<h2>Release 0.5.6 - Feb 19, 2012</h2>
<ul>
<li><a href="https://github.com/b3log/b3log-solo/issues/130">130 登录用户评论时无需输入验证码</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span>&nbsp;<span style='background: #02e10c !important;color:#FFFFFF !important;padding: 1px 4px;'>feature</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/150">150 支持 H2 数据库</a>&nbsp;<span style='background: #02e10c !important;color:#FFFFFF !important;padding: 1px 4px;'>feature</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/171">171 新皮肤 timeline</a>&nbsp;<span style='background: #02e10c !important;color:#FFFFFF !important;padding: 1px 4px;'>feature</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/133">133 前端代理后在线人数不正常</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/141">141 请求 Latke Remote APIs 时跳过初始化检查</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/142">142 保存为草稿后再发布无法同步</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/148">148 清空数据存储时未删除插件存储</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/149">149 “随机阅读”/“相关阅读”链接错误</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/151">151 OpenShift 上不显示验证码</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/159">159 加密文章问题</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/160">160 本地版内存溢出</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/164">164 robots.txt 禁止抓取标签问题</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/169">169 DateFormat 线程安全问题</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span>&nbsp;<span style='background: #e102d8 !important;color:#FFFFFF !important;padding: 1px 4px;'>development</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/170">170 登录页面底部链接问题</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/172">172 GAE 版配额消耗过快问题</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/177">177 泄漏用户密码安全问题</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/129">129 摘要编辑器添加源码功能</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/132">132 Markdown 编辑器显示问题</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/154">154 使用密文存储密码</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/155">155 邮件 SSL 配置</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/162">162 404 页面引入公益活动</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/173">173 评论快捷键提交</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/175">175 社区同步文案</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/176">176 更新文章提示改进</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/147">147 工程中加入 eclipse 项目配置</a>&nbsp;<span style='background: #e102d8 !important;color:#FFFFFF !important;padding: 1px 4px;'>development</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/161">161 使用 mvn 插件统一 Java 格式化 </a>&nbsp;<span style='background: #e102d8 !important;color:#FFFFFF !important;padding: 1px 4px;'>development</span></li>
</ul>
<h2>Release 0.5.5 - Nov 24, 2012</h2>
<ul>
<li><a href="https://github.com/b3log/b3log-solo/issues/72">72 非管理员登录后 TopBar 无后台入口</a></li>
......
......@@ -20,3 +20,4 @@ Join B3log Team: https://github.com/b3log/b3log-solo/wiki/Join_us
Equality, Freedom, Passion
;-)
......@@ -37,6 +37,7 @@ Without this configuration present, some functionality in the IDE may be limited
<word>sitemap</word>
<word>struct</word>
<word>structs</word>
<word>Swithches</word>
<word>Upgrader</word>
<word>Upgraders</word>
</spellchecker-wordlist>
......
<?xml version="1.0" encoding="UTF-8"?>
<!--
Description: B3log Solo core.
Version: 2.0.1.2, Feb 4, 2013
Version: 2.0.1.3, Apr 26, 2013
Author: Liang Ding
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
......@@ -17,7 +17,7 @@
<parent>
<groupId>org.b3log</groupId>
<artifactId>solo</artifactId>
<version>0.5.6</version>
<version>0.6.0</version>
</parent>
<dependencies>
......
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: org.b3log:latke:0.5.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: org.freemarker:freemarker:2.3.19" level="project" />
<orderEntry type="library" name="Maven: javax.mail:mail:1.4" level="project" />
<orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
<orderEntry type="library" name="Maven: commons-io:commons-io:1.4" level="project" />
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.5" level="project" />
<orderEntry type="library" name="Maven: javassist:javassist:3.12.1.GA" level="project" />
<orderEntry type="library" name="Maven: com.jolbox:bonecp:0.7.1.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:guava:r08" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.5.10" level="project" />
<orderEntry type="library" name="Maven: c3p0:c3p0:0.9.1.2" level="project" />
<orderEntry type="library" name="Maven: com.h2database:h2:1.3.170" level="project" />
<orderEntry type="library" name="Maven: org.jboss:jboss-vfs:3.1.0.Final" level="project" />
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.0.0.CR1" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: javax.servlet:servlet-api:2.5" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.testng:testng:6.1.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:3.8.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.beanshell:bsh:2.0b4" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.beust:jcommander:1.12" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.yaml:snakeyaml:1.6" level="project" />
<orderEntry type="library" name="Maven: org.jsoup:jsoup:1.5.2" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.b3log:latke-gae:0.5.0-SNAPSHOT" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.google.appengine:appengine-api-1.0-sdk:1.7.7" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.google.appengine:appengine-api-labs:1.7.7" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.google.appengine:appengine-api-stubs:1.7.7" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.google.appengine:appengine-testing:1.7.7" level="project" />
<orderEntry type="library" name="Maven: org.tautua.markdownpapers:markdownpapers-core:1.3.2" level="project" />
</component>
</module>
......@@ -16,6 +16,7 @@
package org.b3log.solo;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContextEvent;
......@@ -34,12 +35,14 @@ import org.b3log.latke.util.Requests;
import org.b3log.latke.util.Stopwatchs;
import org.b3log.latke.util.Strings;
import org.b3log.latke.util.freemarker.Templates;
import org.b3log.solo.event.cache.RemoveCacheListener;
import org.b3log.solo.event.comment.ArticleCommentReplyNotifier;
import org.b3log.solo.event.comment.PageCommentReplyNotifier;
import org.b3log.solo.event.ping.AddArticleGoogleBlogSearchPinger;
import org.b3log.solo.event.ping.UpdateArticleGoogleBlogSearchPinger;
import org.b3log.solo.event.plugin.PluginRefresher;
import org.b3log.solo.event.rhythm.ArticleSender;
import org.b3log.solo.event.rhythm.ArticleUpdater;
import org.b3log.solo.event.symphony.CommentSender;
import org.b3log.solo.model.Preference;
import org.b3log.solo.model.Skin;
......@@ -55,7 +58,7 @@ import org.json.JSONObject;
* B3log Solo servlet listener.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.7.7, Feb 4, 2013
* @version 1.0.9.9, Apr 26, 2013
* @since 0.3.1
*/
public final class SoloServletListener extends AbstractServletListener {
......@@ -63,7 +66,7 @@ public final class SoloServletListener extends AbstractServletListener {
/**
* B3log Solo version.
*/
public static final String VERSION = "0.5.6";
public static final String VERSION = "0.6.0";
/**
* Logger.
......@@ -80,6 +83,23 @@ public final class SoloServletListener extends AbstractServletListener {
*/
public static final String ENTER_ESC = "_esc_enter_88250_";
/**
* B3log Rhythm address.
*/
public static final String B3LOG_RHYTHM_SERVE_PATH;
/**
* B3log Symphony address.
*/
public static final String B3LOG_SYMPHONY_SERVE_PATH;
static {
final ResourceBundle b3log = ResourceBundle.getBundle("b3log");
B3LOG_RHYTHM_SERVE_PATH = b3log.getString("rhythm.servePath");
B3LOG_SYMPHONY_SERVE_PATH = b3log.getString("symphony.servePath");
}
@Override
public void contextInitialized(final ServletContextEvent servletContextEvent) {
Stopwatchs.start("Context Initialized");
......@@ -235,15 +255,21 @@ public final class SoloServletListener extends AbstractServletListener {
try {
final EventManager eventManager = EventManager.getInstance();
// Comment
eventManager.registerListener(new ArticleCommentReplyNotifier());
eventManager.registerListener(new PageCommentReplyNotifier());
// Article
eventManager.registerListener(new AddArticleGoogleBlogSearchPinger());
eventManager.registerListener(new UpdateArticleGoogleBlogSearchPinger());
// Plugin
eventManager.registerListener(new PluginRefresher());
eventManager.registerListener(new ViewLoadEventHandler());
// Sync
eventManager.registerListener(new ArticleSender());
eventManager.registerListener(new ArticleUpdater());
eventManager.registerListener(new CommentSender());
// Cache
eventManager.registerListener(new RemoveCacheListener());
} catch (final Exception e) {
LOGGER.log(Level.SEVERE, "Register event processors error", e);
throw new IllegalStateException(e);
......
......@@ -73,7 +73,7 @@ import org.jsoup.Jsoup;
* </p>
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.9, Jan 30, 2013
* @version 1.0.0.10, Mar 19, 2013
* @since 0.4.0
*/
@RequestProcessor
......@@ -291,7 +291,6 @@ public final class MetaWeblogAPI {
} catch (final Exception e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
responseContent = "";
final StringBuilder stringBuilder = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?><methodResponse>").append("<fault><value><struct>").append("<member><name>faultCode</name><value><int>500</int></value></member>").append("<member><name>faultString</name><value><string>").append(e.getMessage()).append(
"</string></value></member></struct></value></fault></methodResponse>");
......@@ -361,17 +360,16 @@ public final class MetaWeblogAPI {
final String name = member.getString("name");
if ("dateCreated".equals(name)) {
final JSONObject preference = preferenceQueryService.getPreference();
final String dateString = member.getJSONObject("value").getString("dateTime.iso8601");
Date date = null;
Date date;
try {
date = (Date) DateFormatUtils.ISO_DATETIME_FORMAT.parseObject(dateString);
} catch (final ParseException e) {
LOGGER.log(Level.WARNING,
"Parses article create date failed with ISO8601, retry to parse with pattern[yyyy-MM-dd'T'HH:mm:ss]");
date = DateUtils.parseDate(dateString, new String[] {"yyyyMMdd'T'HH:mm:ss"});
"Parses article create date failed with ISO8601, retry to parse with "
+ "pattern[yyyy-MM-dd'T'HH:mm:ss, yyyyMMdd'T'HH:mm:ss'Z']");
date = DateUtils.parseDate(dateString, new String[] {"yyyyMMdd'T'HH:mm:ss", "yyyyMMdd'T'HH:mm:ss'Z'"});
}
ret.put(Article.ARTICLE_CREATE_DATE, date);
} else if ("title".equals(name)) {
......
......@@ -33,6 +33,7 @@ import org.b3log.solo.model.Article;
import org.b3log.solo.model.Common;
import org.b3log.solo.model.Preference;
import org.b3log.solo.service.ArticleMgmtService;
import org.b3log.solo.service.ArticleQueryService;
import org.b3log.solo.service.PreferenceQueryService;
import org.b3log.solo.service.UserQueryService;
import org.b3log.solo.util.QueryResults;
......@@ -44,7 +45,7 @@ import org.jsoup.Jsoup;
* Article receiver (from B3log Symphony).
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.4, Jan 4, 2013
* @version 1.0.0.5, Mar 18, 2013
* @since 0.5.5
*/
@RequestProcessor
......@@ -65,6 +66,11 @@ public final class ArticleReceiver {
*/
private ArticleMgmtService articleMgmtService = ArticleMgmtService.getInstance();
/**
* Article query service.
*/
private ArticleQueryService articleQueryService = ArticleQueryService.getInstance();
/**
* Article abstract length.
*/
......@@ -101,7 +107,7 @@ public final class ArticleReceiver {
* @param context the specified http request context
* @throws Exception exception
*/
@RequestProcessing(value = "/apis/symphony/article", method = HTTPRequestMethod.PUT)
@RequestProcessing(value = "/apis/symphony/article", method = HTTPRequestMethod.POST)
public void addArticle(final HttpServletRequest request, final HttpServletResponse response, final HTTPRequestContext context)
throws Exception {
final JSONRenderer renderer = new JSONRenderer();
......@@ -135,14 +141,14 @@ public final class ArticleReceiver {
article.put(Article.ARTICLE_ABSTRACT, plainTextContent);
}
article.put(Article.ARTICLE_IS_PUBLISHED, true);
article.put(Common.POST_TO_COMMUNITY, false);
article.put(Common.POST_TO_COMMUNITY, false); // Do not send to rhythm
article.put(Article.ARTICLE_COMMENTABLE, true);
article.put(Article.ARTICLE_VIEW_PWD, "");
String content = article.getString(Article.ARTICLE_CONTENT);
final String articleId = article.getString(Keys.OBJECT_ID);
content += "<br/><br/><p style='font-size: 12px;'><i>该文章同步自 <a href='http://symphony.b3log.org/article/" + articleId
+ "' target='_blank>B3log 社区</a></i></p>";
+ "' target='_blank'>B3log 社区</a></i></p>";
article.put(Article.ARTICLE_CONTENT, content);
articleMgmtService.addArticle(requestJSONObject);
......@@ -161,4 +167,98 @@ public final class ArticleReceiver {
jsonObject.put(Keys.MSG, e.getMessage());
}
}
/**
* Updates an article with the specified request.
*
* <p>
* Renders the response with a json object, for example,
* <pre>
* {
* "sc": boolean,
* "msg": ""
* }
* </pre>
* </p>
*
* @param request the specified http servlet request, for example,
* <pre>
* {
* "article": {
* "oId": "", // Symphony Article#clientArticleId
* "articleTitle": "",
* "articleContent": "",
* "articleTags": "tag1,tag2,tag3",
* "userB3Key": "",
* "articleEditorType": ""
* }
* }
* </pre>
* @param response the specified http servlet response
* @param context the specified http request context
* @throws Exception exception
*/
@RequestProcessing(value = "/apis/symphony/article", method = HTTPRequestMethod.PUT)
public void updateArticle(final HttpServletRequest request, final HttpServletResponse response, final HTTPRequestContext context)
throws Exception {
final JSONRenderer renderer = new JSONRenderer();
context.setRenderer(renderer);
final JSONObject ret = new JSONObject();
renderer.setJSONObject(ret);
try {
final JSONObject requestJSONObject = Requests.parseRequestJSONObject(request, response);
final JSONObject article = requestJSONObject.optJSONObject(Article.ARTICLE);
final String userB3Key = article.optString("userB3Key");
final JSONObject preference = preferenceQueryService.getPreference();
if (!userB3Key.equals(preference.optString(Preference.KEY_OF_SOLO))) {
LOGGER.log(Level.WARNING, "B3 key not match, ignored update article");
return;
}
article.remove("userB3Key");
final String articleId = article.getString(Keys.OBJECT_ID);
if (null == articleQueryService.getArticleById(articleId)) {
ret.put(Keys.MSG, "No found article[oId=" + articleId + "] to update");
ret.put(Keys.STATUS_CODE, false);
return;
}
final String plainTextContent = Jsoup.parse(article.optString(Article.ARTICLE_CONTENT)).text();
if (plainTextContent.length() > ARTICLE_ABSTRACT_LENGTH) {
article.put(Article.ARTICLE_ABSTRACT, plainTextContent.substring(0, ARTICLE_ABSTRACT_LENGTH) + "....");
} else {
article.put(Article.ARTICLE_ABSTRACT, plainTextContent);
}
article.put(Article.ARTICLE_IS_PUBLISHED, true);
article.put(Common.POST_TO_COMMUNITY, false); // Do not send to rhythm
article.put(Article.ARTICLE_COMMENTABLE, true);
article.put(Article.ARTICLE_VIEW_PWD, "");
String content = article.getString(Article.ARTICLE_CONTENT);
content += "<br/><br/><p style='font-size: 12px;'><i>该文章同步自 <a href='http://symphony.b3log.org/article/" + articleId
+ "' target='_blank'>B3log 社区</a></i></p>";
article.put(Article.ARTICLE_CONTENT, content);
articleMgmtService.updateArticle(requestJSONObject);
ret.put(Keys.MSG, "update article succ");
ret.put(Keys.STATUS_CODE, true);
} catch (final ServiceException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
final JSONObject jsonObject = QueryResults.defaultResult();
renderer.setJSONObject(jsonObject);
jsonObject.put(Keys.MSG, e.getMessage());
}
}
}
......@@ -17,6 +17,7 @@ package org.b3log.solo.api.symphony;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.List;
......@@ -66,7 +67,7 @@ import org.json.JSONObject;
* Comment receiver (from B3log Symphony).
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.5, Jan 18, 2013
* @version 1.0.0.6, Mar 18, 2013
* @since 0.5.5
*/
@RequestProcessor
......@@ -187,7 +188,19 @@ public final class CommentReceiver {
final String commentName = symphonyCmt.getString("commentAuthorName");
final String commentEmail = symphonyCmt.getString("commentAuthorEmail").trim().toLowerCase();
final String commentURL = "http://" + symphonyCmt.optString("commentAuthorURL");
String commentURL = symphonyCmt.optString("commentAuthorURL");
if (!commentURL.contains("://")) {
commentURL = "http://" + commentURL;
}
try {
new URL(commentURL);
} catch (final MalformedURLException e) {
LOGGER.log(Level.WARNING, "The comment URL is invalid [{0}]", commentURL);
commentURL = "";
}
final String commentId = symphonyCmt.optString(Keys.OBJECT_ID);
String commentContent = symphonyCmt.getString(Comment.COMMENT_CONTENT);
......
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.b3log.solo.event.cache;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.b3log.latke.cache.PageCaches;
import org.b3log.latke.event.AbstractEventListener;
import org.b3log.latke.event.Event;
import org.b3log.latke.event.EventException;
import org.b3log.latke.service.ServiceException;
import org.b3log.solo.service.StatisticMgmtService;
/**
* This listener is responsible for handling remove cache event.
*
* <p>
* Flush the statistic to repository.
* </p>
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.1, Nov 28, 2011
* @since 0.3.1
*/
public final class RemoveCacheListener extends AbstractEventListener<Void> {
/**
* Logger.
*/
private static final Logger LOGGER = Logger.getLogger(RemoveCacheListener.class.getName());
/**
* Statistic management service.
*/
private StatisticMgmtService statisticMgmtService = StatisticMgmtService.getInstance();
@Override
public void action(final Event<Void> event) throws EventException {
LOGGER.log(Level.FINER, "Processing an event[type={0} in listener[className={2}]",
new Object[] {event.getType(), RemoveCacheListener.class.getName()});
try {
statisticMgmtService.flushStatistic();
} catch (final ServiceException e) {
LOGGER.log(Level.SEVERE, "Flushes statistic to repository failed", e);
}
}
/**
* Gets the event type {@linkplain PageCaches#REMOVE_CACHE}.
*
* @return event type
*/
@Override
public String getEventType() {
return PageCaches.REMOVE_CACHE;
}
}
......@@ -30,7 +30,6 @@ import org.b3log.latke.servlet.HTTPRequestMethod;
import org.b3log.latke.urlfetch.HTTPRequest;
import org.b3log.latke.urlfetch.URLFetchService;
import org.b3log.latke.urlfetch.URLFetchServiceFactory;
import org.b3log.latke.util.Strings;
import org.b3log.solo.SoloServletListener;
import org.b3log.solo.event.EventTypes;
import org.b3log.solo.model.Article;
......@@ -43,9 +42,13 @@ import org.json.JSONObject;
/**
* This listener is responsible for sending article to B3log Rhythm.
*
* <p>
* The B3log Rhythm article update interface: http://rhythm.b3log.org/article (POST).
* </p>
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @author ArmstrongCN
* @version 1.0.2.4, Jan 4, 2013
* @version 1.0.2.6, Apr 16, 2013
* @since 0.3.1
*/
public final class ArticleSender extends AbstractEventListener<JSONObject> {
......@@ -65,11 +68,6 @@ public final class ArticleSender extends AbstractEventListener<JSONObject> {
*/
private PreferenceQueryService preferenceQueryService = PreferenceQueryService.getInstance();
/**
* B3log Rhythm address.
*/
public static final String B3LOG_RHYTHM_ADDRESS = "http://rhythm.b3log.org:80";
/**
* URL of adding article to Rhythm.
*/
......@@ -77,7 +75,7 @@ public final class ArticleSender extends AbstractEventListener<JSONObject> {
static {
try {
ADD_ARTICLE_URL = new URL(B3LOG_RHYTHM_ADDRESS + "/add-article.do");
ADD_ARTICLE_URL = new URL(SoloServletListener.B3LOG_RHYTHM_SERVE_PATH + "/article");
} catch (final MalformedURLException e) {
LOGGER.log(Level.SEVERE, "Creates remote service address[rhythm add article] error!");
throw new IllegalStateException(e);
......@@ -105,9 +103,7 @@ public final class ArticleSender extends AbstractEventListener<JSONObject> {
throw new EventException("Not found preference");
}
// Use configured host if Preference.BLOG_HOST is empty.
final String perferHost = preference.getString(Preference.BLOG_HOST);
final String blogHost = !Strings.isEmptyOrNull(perferHost) ? perferHost.toLowerCase() : Latkes.getServePath().toLowerCase();
final String blogHost = Latkes.getServePath();
if (blogHost.contains("localhost")) {
LOGGER.log(Level.INFO, "Blog Solo runs on local server, so should not send this article[id={0}, title={1}] to Rhythm",
......
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.b3log.solo.event.rhythm;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.b3log.latke.Keys;
import org.b3log.latke.Latkes;
import org.b3log.latke.event.AbstractEventListener;
import org.b3log.latke.event.Event;
import org.b3log.latke.event.EventException;
import org.b3log.latke.servlet.HTTPRequestMethod;
import org.b3log.latke.urlfetch.HTTPRequest;
import org.b3log.latke.urlfetch.URLFetchService;
import org.b3log.latke.urlfetch.URLFetchServiceFactory;
import org.b3log.solo.SoloServletListener;
import org.b3log.solo.event.EventTypes;
import org.b3log.solo.model.Article;
import org.b3log.solo.model.Common;
import org.b3log.solo.model.Preference;
import org.b3log.solo.service.PreferenceQueryService;
import org.json.JSONObject;
/**
* This listener is responsible for updating article to B3log Rhythm.
*
* <p>
* The B3log Rhythm article update interface: http://rhythm.b3log.org/article (PUT).
* </p>
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Mar 19, 2013
* @since 0.6.0
*/
public final class ArticleUpdater extends AbstractEventListener<JSONObject> {
/**
* Logger.
*/
private static final Logger LOGGER = Logger.getLogger(ArticleUpdater.class.getName());
/**
* URL fetch service.
*/
private final URLFetchService urlFetchService = URLFetchServiceFactory.getURLFetchService();
/**
* Preference query service.
*/
private PreferenceQueryService preferenceQueryService = PreferenceQueryService.getInstance();
/**
* URL of updating article to Rhythm.
*/
private static final URL UPDATE_ARTICLE_URL;
static {
try {
UPDATE_ARTICLE_URL = new URL(SoloServletListener.B3LOG_RHYTHM_SERVE_PATH + "/article");
} catch (final MalformedURLException e) {
LOGGER.log(Level.SEVERE, "Creates remote service address[rhythm update article] error!");
throw new IllegalStateException(e);
}
}
@Override
public void action(final Event<JSONObject> event) throws EventException {
final JSONObject data = event.getData();
LOGGER.log(Level.FINER, "Processing an event[type={0}, data={1}] in listener[className={2}]",
new Object[] {event.getType(), data, ArticleUpdater.class.getName()});
try {
final JSONObject originalArticle = data.getJSONObject(Article.ARTICLE);
if (!originalArticle.getBoolean(Article.ARTICLE_IS_PUBLISHED)) {
LOGGER.log(Level.FINER, "Ignores post article[title={0}] to Rhythm", originalArticle.getString(Article.ARTICLE_TITLE));
return;
}
final JSONObject preference = preferenceQueryService.getPreference();
if (null == preference) {
throw new EventException("Not found preference");
}
final String blogHost = Latkes.getServePath();
if (blogHost.contains("localhost")) {
LOGGER.log(Level.INFO, "Blog Solo runs on local server, so should not send this article[id={0}, title={1}] to Rhythm",
new Object[] {originalArticle.getString(Keys.OBJECT_ID), originalArticle.getString(Article.ARTICLE_TITLE)});
return;
}
final HTTPRequest httpRequest = new HTTPRequest();
httpRequest.setURL(UPDATE_ARTICLE_URL);
httpRequest.setRequestMethod(HTTPRequestMethod.PUT);
final JSONObject requestJSONObject = new JSONObject();
final JSONObject article = new JSONObject();
article.put(Keys.OBJECT_ID, originalArticle.getString(Keys.OBJECT_ID));
article.put(Article.ARTICLE_TITLE, originalArticle.getString(Article.ARTICLE_TITLE));
article.put(Article.ARTICLE_PERMALINK, originalArticle.getString(Article.ARTICLE_PERMALINK));
article.put(Article.ARTICLE_TAGS_REF, originalArticle.getString(Article.ARTICLE_TAGS_REF));
article.put(Article.ARTICLE_AUTHOR_EMAIL, originalArticle.getString(Article.ARTICLE_AUTHOR_EMAIL));
article.put(Article.ARTICLE_CONTENT, originalArticle.getString(Article.ARTICLE_CONTENT));
article.put(Article.ARTICLE_CREATE_DATE, ((Date) originalArticle.get(Article.ARTICLE_CREATE_DATE)).getTime());
article.put(Common.POST_TO_COMMUNITY, originalArticle.getBoolean(Common.POST_TO_COMMUNITY));
// Removes this property avoid to persist
originalArticle.remove(Common.POST_TO_COMMUNITY);
requestJSONObject.put(Article.ARTICLE, article);
requestJSONObject.put(Common.BLOG_VERSION, SoloServletListener.VERSION);
requestJSONObject.put(Common.BLOG, "B3log Solo");
requestJSONObject.put(Preference.BLOG_TITLE, preference.getString(Preference.BLOG_TITLE));
requestJSONObject.put(Preference.BLOG_HOST, blogHost);
requestJSONObject.put("userB3Key", preference.optString(Preference.KEY_OF_SOLO));
requestJSONObject.put("clientAdminEmail", preference.optString(Preference.ADMIN_EMAIL));
requestJSONObject.put("clientRuntimeEnv", Latkes.getRuntimeEnv().name());
httpRequest.setPayload(requestJSONObject.toString().getBytes("UTF-8"));
urlFetchService.fetchAsync(httpRequest);
} catch (final Exception e) {
LOGGER.log(Level.SEVERE, "Sends an article to Rhythm error: {0}", e.getMessage());
}
LOGGER.log(Level.FINER, "Sent an article to Rhythm");
}
/**
* Gets the event type {@linkplain EventTypes#UPDATE_ARTICLE}.
*
* @return event type
*/
@Override
public String getEventType() {
return EventTypes.UPDATE_ARTICLE;
}
}
......@@ -42,7 +42,7 @@ import org.json.JSONObject;
* This listener is responsible for sending comment to B3log Symphony.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.2, Nov 20, 2012
* @version 1.0.0.3, Mar 5, 2013
* @since 0.5.5
*/
public final class CommentSender extends AbstractEventListener<JSONObject> {
......@@ -62,11 +62,6 @@ public final class CommentSender extends AbstractEventListener<JSONObject> {
*/
private PreferenceQueryService preferenceQueryService = PreferenceQueryService.getInstance();
/**
* B3log Symphony address.
*/
public static final String B3LOG_SYMPHONY_ADDRESS = "http://symphony.b3log.org:80";
/**
* URL of adding comment to Symphony.
*/
......@@ -74,7 +69,7 @@ public final class CommentSender extends AbstractEventListener<JSONObject> {
static {
try {
ADD_COMMENT_URL = new URL(B3LOG_SYMPHONY_ADDRESS + "/solo/comment");
ADD_COMMENT_URL = new URL(SoloServletListener.B3LOG_SYMPHONY_SERVE_PATH + "/solo/comment");
} catch (final MalformedURLException e) {
LOGGER.log(Level.SEVERE, "Creates remote service address[symphony add comment] error!");
throw new IllegalStateException(e);
......@@ -107,7 +102,7 @@ public final class CommentSender extends AbstractEventListener<JSONObject> {
final HTTPRequest httpRequest = new HTTPRequest();
httpRequest.setURL(ADD_COMMENT_URL);
httpRequest.setRequestMethod(HTTPRequestMethod.PUT);
httpRequest.setRequestMethod(HTTPRequestMethod.POST);
final JSONObject requestJSONObject = new JSONObject();
final JSONObject comment = new JSONObject();
......
......@@ -20,8 +20,8 @@ package org.b3log.solo.model;
* This class defines all common model relevant keys.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @author <a href="mailto:dongxv.vang@gmail.com">Dongxu Wang</a>
* @version 1.0.4.9, Jan 22, 2013
* @author <a href="mailto:dongxu.wang@acm.org">Dongxu Wang</a>
* @version 1.0.5.0, Mar 11, 2013
* @since 0.3.1
*/
public final class Common {
......
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.b3log.solo.model;
/**
* This class defines option model relevant keys.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Apr 15, 2013
* @since 0.6.0
*/
public final class Option {
/**
* Option.
*/
public static final String OPTION = "option";
/**
* Options.
*/
public static final String OPTIONS = "options";
/**
* Key of option value.
*/
public static final String OPTION_VALUE = "optionValue";
/**
* Key of option category.
*/
public static final String OPTION_CATEGORY = "optionCategory";
// oId constants
/**
* Key of broadcast chance expiration time.
*/
public static final String ID_C_BROADCAST_CHANCE_EXPIRATION_TIME = "broadcastChanceExpirationTime";
// Category constants
/**
* Broadcast.
*/
public static final String CATEGORY_C_BROADCAST = "broadcast";
/**
* Private constructor.
*/
private Option() {}
}
......@@ -29,7 +29,7 @@ import org.json.JSONObject;
* This class defines all comment model relevant keys.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.1.0.7, Sep 10, 2012
* @version 1.1.0.8, Mar 5, 2013
* @since 0.3.1
*/
public final class Preference {
......@@ -206,6 +206,11 @@ public final class Preference {
*/
public static final String FEED_OUTPUT_MODE = "feedOutputMode";
/**
* Key of feed (Atom/RSS) output entry count.
*/
public static final String FEED_OUTPUT_CNT = "feedOutputCnt";
/**
* Key of editor type.
*
......@@ -390,6 +395,11 @@ public final class Preference {
*/
public static final String DEFAULT_FEED_OUTPUT_MODE = "abstract";
/**
* Default feed output entry count.
*/
public static final int DEFAULT_FEED_OUTPUT_CNT = 10;
/**
* Default editor type.
*/
......
......@@ -68,7 +68,7 @@ import org.jsoup.Jsoup;
* Article processor.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.1.2.9, Feb 5, 2013
* @version 1.1.2.10, Mar 26, 2013
* @since 0.3.1
*/
@RequestProcessor
......@@ -124,11 +124,6 @@ public final class ArticleProcessor {
*/
private UserQueryService userQueryService = UserQueryService.getInstance();
/**
* Default update count for article random value.
*/
private static final int DEFAULT_UPDATE_CNT = 10;
/**
* Shows the article view password form.
*
......@@ -953,6 +948,10 @@ public final class ArticleProcessor {
filler.fillSide(request, dataModel, preference);
Skins.fillSkinLangs(preference.optString(Preference.LOCALE_STRING), (String) request.getAttribute(Keys.TEMAPLTE_DIR_NAME),
dataModel);
if (!Requests.hasBeenServed(request, response)) {
ArticleMgmtService.getInstance().incViewCount(articleId);
}
} catch (final Exception e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
......
......@@ -69,7 +69,7 @@ import org.json.JSONObject;
* Feed (Atom/RSS) processor.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.1.0.2, Nov 15, 2012
* @version 1.1.0.3, Mar 5, 2013
* @since 0.3.1
*/
@RequestProcessor
......@@ -90,11 +90,6 @@ public final class FeedProcessor {
*/
private PreferenceQueryService preferenceQueryService = PreferenceQueryService.getInstance();
/**
* Count of output entry.
*/
public static final int ENTRY_OUTPUT_CNT = 10;
/**
* Article utilities.
*/
......@@ -129,6 +124,7 @@ public final class FeedProcessor {
final String blogTitle = preference.getString(Preference.BLOG_TITLE);
final String blogSubtitle = preference.getString(Preference.BLOG_SUBTITLE);
final String blogHost = preference.getString(Preference.BLOG_HOST);
final int outputCnt = preference.getInt(Preference.FEED_OUTPUT_CNT);
feed.setTitle(StringEscapeUtils.escapeXml(blogTitle));
feed.setSubtitle(StringEscapeUtils.escapeXml(blogSubtitle));
......@@ -141,7 +137,7 @@ public final class FeedProcessor {
filters.add(new PropertyFilter(Article.ARTICLE_IS_PUBLISHED, FilterOperator.EQUAL, true));
filters.add(new PropertyFilter(Article.ARTICLE_VIEW_PWD, FilterOperator.EQUAL, ""));
final Query query = new Query().setCurrentPageNum(1).setPageSize(ENTRY_OUTPUT_CNT).setFilter(new CompositeFilter(CompositeFilterOperator.AND, filters)).addSort(Article.ARTICLE_UPDATE_DATE, SortDirection.DESCENDING).setPageCount(
final Query query = new Query().setCurrentPageNum(1).setPageSize(outputCnt).setFilter(new CompositeFilter(CompositeFilterOperator.AND, filters)).addSort(Article.ARTICLE_UPDATE_DATE, SortDirection.DESCENDING).setPageCount(
1);
final boolean hasMultipleUsers = Users.getInstance().hasMultipleUsers();
......@@ -255,6 +251,7 @@ public final class FeedProcessor {
final String blogTitle = preference.getString(Preference.BLOG_TITLE);
final String blogSubtitle = preference.getString(Preference.BLOG_SUBTITLE) + ", " + tagTitle;
final String blogHost = preference.getString(Preference.BLOG_HOST);
final int outputCnt = preference.getInt(Preference.FEED_OUTPUT_CNT);
feed.setTitle(StringEscapeUtils.escapeXml(blogTitle));
feed.setSubtitle(StringEscapeUtils.escapeXml(blogSubtitle));
......@@ -263,7 +260,7 @@ public final class FeedProcessor {
feed.setLink("http://" + blogHost + "/tag-articles-feed.do");
feed.setId("http://" + blogHost + "/");
final JSONObject tagArticleResult = tagArticleRepository.getByTagId(tagId, 1, ENTRY_OUTPUT_CNT);
final JSONObject tagArticleResult = tagArticleRepository.getByTagId(tagId, 1, outputCnt);
final JSONArray tagArticleRelations = tagArticleResult.getJSONArray(Keys.RESULTS);
if (0 == tagArticleRelations.length()) {
......@@ -368,6 +365,7 @@ public final class FeedProcessor {
final String blogTitle = preference.getString(Preference.BLOG_TITLE);
final String blogSubtitle = preference.getString(Preference.BLOG_SUBTITLE);
final String blogHost = preference.getString(Preference.BLOG_HOST);
final int outputCnt = preference.getInt(Preference.FEED_OUTPUT_CNT);
channel.setTitle(StringEscapeUtils.escapeXml(blogTitle));
channel.setLastBuildDate(TimeZones.getTime(preference.getString(Preference.TIME_ZONE_ID)));
......@@ -385,7 +383,7 @@ public final class FeedProcessor {
filters.add(new PropertyFilter(Article.ARTICLE_IS_PUBLISHED, FilterOperator.EQUAL, true));
filters.add(new PropertyFilter(Article.ARTICLE_VIEW_PWD, FilterOperator.EQUAL, ""));
final Query query = new Query().setCurrentPageNum(1).setPageSize(ENTRY_OUTPUT_CNT).setFilter(new CompositeFilter(CompositeFilterOperator.AND, filters)).addSort(Article.ARTICLE_UPDATE_DATE, SortDirection.DESCENDING).setPageCount(
final Query query = new Query().setCurrentPageNum(1).setPageSize(outputCnt).setFilter(new CompositeFilter(CompositeFilterOperator.AND, filters)).addSort(Article.ARTICLE_UPDATE_DATE, SortDirection.DESCENDING).setPageCount(
1);
final JSONObject articleResult = articleRepository.get(query);
......@@ -501,6 +499,7 @@ public final class FeedProcessor {
final String blogTitle = preference.getString(Preference.BLOG_TITLE);
final String blogSubtitle = preference.getString(Preference.BLOG_SUBTITLE) + ", " + tagTitle;
final String blogHost = preference.getString(Preference.BLOG_HOST);
final int outputCnt = preference.getInt(Preference.FEED_OUTPUT_CNT);
channel.setTitle(StringEscapeUtils.escapeXml(blogTitle));
channel.setLastBuildDate(TimeZones.getTime(preference.getString(Preference.TIME_ZONE_ID)));
......@@ -514,7 +513,7 @@ public final class FeedProcessor {
channel.setLanguage(language + '-' + country);
channel.setDescription(blogSubtitle);
final JSONObject tagArticleResult = tagArticleRepository.getByTagId(tagId, 1, ENTRY_OUTPUT_CNT);
final JSONObject tagArticleResult = tagArticleRepository.getByTagId(tagId, 1, outputCnt);
final JSONArray tagArticleRelations = tagArticleResult.getJSONArray(Keys.RESULTS);
if (0 == tagArticleRelations.length()) {
......
......@@ -55,7 +55,8 @@ import org.json.JSONObject;
* Index processor.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.1.1.0, Oct 11, 2012
* @author <a href="mailto:385321165@qq.com">DASHU</a>
* @version 1.1.1.2, Apr 1, 2013
* @since 0.3.1
*/
@RequestProcessor
......@@ -188,6 +189,45 @@ public final class IndexProcessor {
}
}
/**
* Show register page.
*
* @param context the specified context
* @param request the specified HTTP servlet request
* @param response the specified HTTP servlet response
*/
@RequestProcessing(value = "/register", method = HTTPRequestMethod.GET)
public void register(final HTTPRequestContext context, final HttpServletRequest request, final HttpServletResponse response) {
final AbstractFreeMarkerRenderer renderer = new ConsoleRenderer();
context.setRenderer(renderer);
renderer.setTemplateName("register.ftl");
final Map<String, Object> dataModel = renderer.getDataModel();
try {
final Map<String, String> langs = langPropsService.getAll(Locales.getLocale(request));
dataModel.putAll(langs);
final JSONObject preference = preferenceQueryService.getPreference();
filler.fillBlogFooter(dataModel, preference);
filler.fillMinified(dataModel);
Keys.fillServer(dataModel);
} catch (final ServiceException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
try {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
} catch (final IOException ex) {
LOGGER.severe(ex.getMessage());
}
}
}
/**
* Gets the request page number from the specified request URI.
*
......
......@@ -329,10 +329,10 @@ public final class RepairProcessor {
htmlBuilder.append("<script type='text/javascript'");
htmlBuilder.append("src='http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js'");
htmlBuilder.append("></script></head><body>");
htmlBuilder.append("<button id='ok' onclick='remove()'>");
htmlBuilder.append("<button id='ok' onclick='removeData()'>");
htmlBuilder.append("Continue to delete ALL DATA</button></body>");
htmlBuilder.append("<script type='text/javascript'>");
htmlBuilder.append("function remove() {");
htmlBuilder.append("function removeData() {");
htmlBuilder.append("$.ajax({type: 'POST',url:'").append(Latkes.getContextPath()).append("/rm-all-data.do',");
htmlBuilder.append("dataType: 'text/html',success: function(result){");
htmlBuilder.append("$('html').html(result);}});}</script></html>");
......
......@@ -16,33 +16,16 @@
package org.b3log.solo.processor;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.b3log.latke.Latkes;
import org.b3log.latke.cache.PageCaches;
import org.b3log.latke.repository.RepositoryException;
import org.b3log.latke.repository.Transaction;
import org.b3log.latke.service.LangPropsService;
import org.b3log.latke.service.ServiceException;
import org.b3log.latke.servlet.HTTPRequestContext;
import org.b3log.latke.servlet.HTTPRequestMethod;
import org.b3log.latke.servlet.annotation.RequestProcessing;
import org.b3log.latke.servlet.annotation.RequestProcessor;
import org.b3log.latke.servlet.renderer.DoNothingRenderer;
import org.b3log.latke.util.CollectionUtils;
import org.b3log.solo.model.Article;
import org.b3log.solo.model.PageTypes;
import org.b3log.solo.model.Statistic;
import org.b3log.solo.repository.ArticleRepository;
import org.b3log.solo.repository.StatisticRepository;
import org.b3log.solo.repository.impl.ArticleRepositoryImpl;
import org.b3log.solo.repository.impl.StatisticRepositoryImpl;
import org.b3log.solo.service.StatisticMgmtService;
import org.b3log.solo.util.Statistics;
import org.json.JSONObject;
/**
......@@ -53,12 +36,11 @@ import org.json.JSONObject;
*
* <ul>
* <li>{@link #viewCounter(org.b3log.latke.servlet.HTTPRequestContext) Blog/Article view counting}</li>
* <li>TODO: 88250, stat proc</li>
* </ul>
* <p>
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.1.7, Jul 24, 2012
* @version 1.0.1.9, Mar 6, 2013
* @since 0.4.0
*/
@RequestProcessor
......@@ -70,24 +52,9 @@ public final class StatProcessor {
private static final Logger LOGGER = Logger.getLogger(StatProcessor.class.getName());
/**
* Statistic repository.
* Statistic management service.
*/
private StatisticRepository statisticRepository = StatisticRepositoryImpl.getInstance();
/**
* Article repository.
*/
private ArticleRepository articleRepository = ArticleRepositoryImpl.getInstance();
/**
* Language service.
*/
private LangPropsService langPropsService = LangPropsService.getInstance();
/**
* Flush size.
*/
private static final int FLUSH_SIZE = 30;
private StatisticMgmtService statisticMgmtService = StatisticMgmtService.getInstance();
/**
* Online visitor count refresher.
......@@ -112,84 +79,10 @@ public final class StatProcessor {
context.setRenderer(new DoNothingRenderer());
final JSONObject statistic = (JSONObject) statisticRepository.getCache().get(
Statistics.REPOSITORY_CACHE_KEY_PREFIX + Statistic.STATISTIC);
if (null == statistic) {
LOGGER.log(Level.INFO, "Not found statistic in memcache, ignores sync");
return;
}
final Transaction transaction = statisticRepository.beginTransaction();
transaction.clearQueryCache(false);
try {
// For blog view counter
statisticRepository.update(Statistic.STATISTIC, statistic);
// For article view counter
final Set<String> keys = PageCaches.getKeys();
final List<String> keyList = new ArrayList<String>(keys);
final int size = keys.size() > FLUSH_SIZE ? FLUSH_SIZE : keys.size(); // Flush FLUSH_SIZE articles at most
final List<Integer> idx = CollectionUtils.getRandomIntegers(0, keys.size(), size);
final Set<String> cachedPageKeys = new HashSet<String>();
for (final Integer i : idx) {
cachedPageKeys.add(keyList.get(i));
}
for (final String cachedPageKey : cachedPageKeys) {
final JSONObject cachedPage = PageCaches.get(cachedPageKey);
if (null == cachedPage) {
continue;
}
final Map<String, String> langs = langPropsService.getAll(Latkes.getLocale());
if (!cachedPage.optString(PageCaches.CACHED_TYPE).equals(langs.get(PageTypes.ARTICLE.getLangeLabel()))) { // Cached is not an article page
continue;
}
final int hitCount = cachedPage.optInt(PageCaches.CACHED_HIT_COUNT);
final String articleId = cachedPage.optString(PageCaches.CACHED_OID);
final JSONObject article = articleRepository.get(articleId);
if (null == article) {
continue;
}
LOGGER.log(Level.FINER, "Updating article[id={0}, title={1}] view count",
new Object[] {articleId, cachedPage.optString(PageCaches.CACHED_TITLE)});
final int oldViewCount = article.optInt(Article.ARTICLE_VIEW_COUNT);
final int viewCount = oldViewCount + hitCount;
article.put(Article.ARTICLE_VIEW_COUNT, viewCount);
article.put(Article.ARTICLE_RANDOM_DOUBLE, Math.random()); // Updates random value
articleRepository.update(articleId, article);
cachedPage.put(PageCaches.CACHED_HIT_COUNT, 0);
LOGGER.log(Level.FINER, "Updating article[id={0}, title={1}] view count from [{2}] to [{3}]",
new Object[] {articleId, article.optString(Article.ARTICLE_TITLE), oldViewCount, viewCount});
}
transaction.commit();
LOGGER.log(Level.INFO, "Synchronized statistic from cache to repository[statistic={0}]", statistic);
} catch (final RepositoryException e) {
if (transaction.isActive()) {
transaction.rollback();
}
LOGGER.log(Level.SEVERE, "Updates statistic failed", e);
statisticMgmtService.flushStatistic();
} catch (final ServiceException e) {
LOGGER.log(Level.SEVERE, "Flushes statistic to repository failed", e);
}
}
}
......@@ -18,7 +18,10 @@ package org.b3log.solo.processor;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.b3log.latke.Keys;
......@@ -26,10 +29,12 @@ import org.b3log.latke.Latkes;
import org.b3log.latke.RuntimeEnv;
import org.b3log.latke.mail.MailService;
import org.b3log.latke.mail.MailServiceFactory;
import org.b3log.latke.model.Plugin;
import org.b3log.latke.model.User;
import org.b3log.latke.repository.*;
import org.b3log.latke.repository.jdbc.JdbcFactory;
import org.b3log.latke.repository.jdbc.util.Connections;
import org.b3log.latke.repository.jdbc.util.FieldDefinition;
import org.b3log.latke.repository.jdbc.util.JdbcRepositories;
import org.b3log.latke.service.LangPropsService;
import org.b3log.latke.service.ServiceException;
import org.b3log.latke.servlet.HTTPRequestContext;
......@@ -37,7 +42,6 @@ import org.b3log.latke.servlet.HTTPRequestMethod;
import org.b3log.latke.servlet.annotation.RequestProcessing;
import org.b3log.latke.servlet.annotation.RequestProcessor;
import org.b3log.latke.servlet.renderer.TextHTMLRenderer;
import org.b3log.latke.util.MD5;
import org.b3log.latke.util.Strings;
import org.b3log.solo.SoloServletListener;
import org.b3log.solo.model.*;
......@@ -53,8 +57,8 @@ import org.json.JSONObject;
* Upgrader.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @author <a href="mailto:dongxv.vang@gmail.com">Dongxu Wang</a>
* @version 1.1.1.7, Feb 19, 2013
* @author <a href="mailto:dongxu.wang@acm.org">Dongxu Wang</a>
* @version 1.1.1.9, Apr 26, 2013
* @since 0.3.1
*/
@RequestProcessor
......@@ -70,11 +74,6 @@ public final class UpgradeProcessor {
*/
private ArticleRepository articleRepository = ArticleRepositoryImpl.getInstance();
/**
* Page repository.
*/
private PageRepository pageRepository = PageRepositoryImpl.getInstance();
/**
* User repository.
*/
......@@ -139,10 +138,10 @@ public final class UpgradeProcessor {
return;
}
if ("0.5.5".equals(version)) {
v055ToV056();
if ("0.5.6".equals(version)) {
v056ToV060();
} else {
LOGGER.log(Level.WARNING, "Attempt to skip more than one version to upgrade. Expected: 0.5.0; Actually: {0}", version);
LOGGER.log(Level.WARNING, "Attempt to skip more than one version to upgrade. Expected: 0.5.6; Actually: {0}", version);
if (!sent) {
notifyUserByEmail();
sent = true;
......@@ -159,12 +158,12 @@ public final class UpgradeProcessor {
}
/**
* Upgrades from version 055 to version 056.
* Upgrades from version 056 to version 060.
*
* @throws Exception upgrade fails
*/
private void v055ToV056() throws Exception {
LOGGER.info("Upgrading from version 055 to version 056....");
private void v056ToV060() throws Exception {
LOGGER.info("Upgrading from version 056 to version 060....");
articleRepository.setCacheEnabled(false);
......@@ -173,14 +172,6 @@ public final class UpgradeProcessor {
try {
transaction = userRepository.beginTransaction();
// Upgrades preference model
final JSONObject preference = preferenceRepository.get(Preference.PREFERENCE);
preference.put(Preference.VERSION, "0.5.6");
preferenceRepository.update(Preference.PREFERENCE, preference);
upgradeUsers();
final RuntimeEnv runtimeEnv = Latkes.getRuntimeEnv();
if (RuntimeEnv.LOCAL == runtimeEnv || RuntimeEnv.BAE == runtimeEnv) {
......@@ -188,12 +179,34 @@ public final class UpgradeProcessor {
final Statement statement = connection.createStatement();
final String tablePrefix = Latkes.getLocalProperty("jdbc.tablePrefix");
final String tableName = Strings.isEmptyOrNull(tablePrefix) ? Plugin.PLUGIN : tablePrefix + '_' + Plugin.PLUGIN;
statement.execute("ALTER TABLE " + tableName + " ADD setting text");
String tableName = Strings.isEmptyOrNull(tablePrefix) ? "preference" : tablePrefix + "_preference";
statement.execute("ALTER TABLE " + tableName + " ADD feedOutputCnt int");
tableName = Strings.isEmptyOrNull(tablePrefix) ? "user" : tablePrefix + "_user";
statement.execute("ALTER TABLE " + tableName + " ADD userURL varchar(255)");
connection.commit();
tableName = Strings.isEmptyOrNull(tablePrefix) ? "option" : tablePrefix + "_option";
final Map<String, List<FieldDefinition>> map = JdbcRepositories.getRepositoriesMap();
try {
JdbcFactory.createJdbcFactory().createTable(tableName, map.get(tableName));
} catch (final SQLException e) {
LOGGER.log(Level.SEVERE, "createTable[" + tableName + "] error", e);
}
}
// Upgrades preference model
final JSONObject preference = preferenceRepository.get(Preference.PREFERENCE);
preference.put(Preference.VERSION, "0.6.0");
preference.put(Preference.FEED_OUTPUT_CNT, Preference.Default.DEFAULT_FEED_OUTPUT_CNT);
preferenceRepository.update(Preference.PREFERENCE, preference);
upgradeUsers();
transaction.commit();
......@@ -204,12 +217,12 @@ public final class UpgradeProcessor {
}
LOGGER.log(Level.SEVERE, "Upgrade failed.", e);
throw new Exception("Upgrade failed from version 055 to version 056");
throw new Exception("Upgrade failed from version 056 to version 060");
} finally {
articleRepository.setCacheEnabled(true);
}
LOGGER.info("Upgraded from version 055 to version 056 successfully :-)");
LOGGER.info("Upgraded from version 056 to version 060 successfully :-)");
}
/**
......@@ -226,9 +239,8 @@ public final class UpgradeProcessor {
for (int i = 0; i < users.length(); i++) {
final JSONObject user = users.getJSONObject(i);
final String oldPwd = user.optString(User.USER_PASSWORD);
user.put(User.USER_PASSWORD, MD5.hash(oldPwd));
user.put(User.USER_URL, Latkes.getServePath());
userRepository.update(user.optString(Keys.OBJECT_ID), user);
......
......@@ -43,7 +43,7 @@ import org.json.JSONObject;
* Preference console request processing.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.4, Aug 9, 2012
* @version 1.0.0.5, Mar 5, 2013
* @since 0.4.0
*/
@RequestProcessor
......@@ -291,6 +291,7 @@ public final class PreferenceConsole {
* "articleListStyle": "", // Optional values: "titleOnly"/"titleAndContent"/"titleAndAbstract"
* "commentable": boolean,
* "feedOutputMode: "" // Optional values: "abstract"/"full"
* "feedOutputCnt": int
* }
* }
* </pre>
......@@ -371,7 +372,8 @@ public final class PreferenceConsole {
* "allowVisitDraftViaPermalink": boolean,
* "articleListStyle": "",
* "commentable": boolean,
* "feedOutputMode: ""
* "feedOutputMode: "",
* "feedOutputCnt": int
* }
* }, see {@link org.b3log.solo.model.Preference} for more details
* </pre>
......@@ -505,6 +507,14 @@ public final class PreferenceConsole {
return true;
}
input = preference.optString(Preference.FEED_OUTPUT_CNT);
if (!isNonNegativeInteger(input)) {
errMsgBuilder.append(langPropsService.get("feedOutputCntLabel")).append("] ").append(
langPropsService.get("nonNegativeIntegerOnlyLabel"));
responseObject.put(Keys.MSG, errMsgBuilder.toString());
return true;
}
return false;
}
......
......@@ -22,6 +22,8 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.b3log.latke.Keys;
import org.b3log.latke.Latkes;
import org.b3log.latke.model.Role;
import org.b3log.latke.model.User;
import org.b3log.latke.service.LangPropsService;
import org.b3log.latke.service.ServiceException;
import org.b3log.latke.servlet.HTTPRequestContext;
......@@ -41,7 +43,8 @@ import org.json.JSONObject;
* User console request processing.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.2, Jan 29, 2013
* @author <a href="mailto:385321165@qq.com">DASHU</a>
* @version 1.0.0.4, Apr 2, 2013
* @since 0.4.0
*/
@RequestProcessor
......@@ -91,8 +94,9 @@ public final class UserConsole {
* "oId": "",
* "userName": "",
* "userEmail": "",
* "userPassword": "",
* "userRole": ""
* "userPassword": "", // Unhashed
* "userRole": "", // optional
* "userURL": "", // optional
* }
* </pre>
* @param context the specified http request context
......@@ -152,8 +156,8 @@ public final class UserConsole {
* "userName": "",
* "userEmail": "",
* "userPassword": "",
* "userRole": "" // optional, uses {@value org.b3log.latke.model.Role#DEFAULT_ROLE} instead,
* if not speciffied
* "userURL": "", // optional, uses 'servePath' instead if not specified
* "userRole": "" // optional, uses {@value org.b3log.latke.model.Role#DEFAULT_ROLE} instead if not speciffied
* }
* </pre>
* @param response the specified http servlet response
......@@ -163,10 +167,6 @@ public final class UserConsole {
@RequestProcessing(value = "/console/user/", method = HTTPRequestMethod.POST)
public void addUser(final HttpServletRequest request, final HttpServletResponse response, final HTTPRequestContext context)
throws Exception {
if (!userUtils.isAdminLoggedIn(request)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
final JSONRenderer renderer = new JSONRenderer();
......@@ -177,6 +177,14 @@ public final class UserConsole {
try {
final JSONObject requestJSONObject = Requests.parseRequestJSONObject(request, response);
if (userUtils.isAdminLoggedIn(request)) { // if the administrator register a new user, treats the new user as a normal user
// (defaultRole) who could post article
requestJSONObject.put(User.USER_ROLE, Role.DEFAULT_ROLE);
} else { // if a normal user or a visitor register a new user, treates the new user as a visitor (visitorRole) who couldn't
// post article
requestJSONObject.put(User.USER_ROLE, Role.VISITOR_ROLE);
}
final String userId = userMgmtService.addUser(requestJSONObject);
ret.put(Keys.OBJECT_ID, userId);
......@@ -368,4 +376,54 @@ public final class UserConsole {
jsonObject.put(Keys.MSG, langPropsService.get("getFailLabel"));
}
}
/**
* Change a user role.
*
* <p>
* Renders the response with a json object, for example,
* <pre>
* {
* "sc": boolean,
* "msg": ""
* }
* </pre>
* </p>
*
* @param request the specified http servlet request
* @param response the specified http servlet response
* @param context the specified http request context
* @throws Exception exception
*/
@RequestProcessing(value = "/console/changeRole/*", method = HTTPRequestMethod.GET)
public void changeUserRole(final HttpServletRequest request, final HttpServletResponse response, final HTTPRequestContext context)
throws Exception {
if (!userUtils.isAdminLoggedIn(request)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
final JSONRenderer renderer = new JSONRenderer();
context.setRenderer(renderer);
final JSONObject jsonObject = new JSONObject();
renderer.setJSONObject(jsonObject);
try {
final String userId = request.getRequestURI().substring((Latkes.getContextPath() + "/console/changeRole/").length());
userMgmtService.changeRole(userId);
jsonObject.put(Keys.STATUS_CODE, true);
jsonObject.put(Keys.MSG, langPropsService.get("updateSuccLabel"));
} catch (final ServiceException e) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
jsonObject.put(Keys.STATUS_CODE, false);
jsonObject.put(Keys.MSG, langPropsService.get("removeFailLabel"));
}
}
}
......@@ -95,6 +95,14 @@ public final class FrontRenderer extends CacheFreeMarkerRenderer {
output = html.replace(Common.TOP_BAR_REPLACEMENT_FLAG, topBarHTML);
}
// Inc blog view count
try {
statistics.incBlogViewCount(request, response);
} catch (final Exception e) {
LOGGER.log(Level.WARNING, "Incs blog view count failed", e);
}
// Write out
writer.write(output);
writer.flush();
writer.close();
......@@ -104,19 +112,13 @@ public final class FrontRenderer extends CacheFreeMarkerRenderer {
* {@inheritDoc}
*
* <p>
* Blog statistic view count +1.
* Skips page caching if requested by mobile device.
* </p>
*/
@Override
protected void afterRender(final HTTPRequestContext context) throws Exception {
LOGGER.log(Level.FINEST, "After render....");
try {
statistics.incBlogViewCount(context.getRequest(), context.getResponse());
} catch (final Exception e) {
LOGGER.log(Level.WARNING, "Incs blog view count failed", e);
}
final HttpServletRequest request = context.getRequest();
if ("mobile".equals((String) request.getAttribute(Keys.TEMAPLTE_DIR_NAME))) {
......
......@@ -48,8 +48,8 @@ import org.json.JSONObject;
* Top bar utilities.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @author <a href="mailto:dongxv.vang@gmail.com">Dongxu Wang</a>
* @version 1.0.0.4, May 4, 2012
* @author <a href="mailto:dongxu.wang@acm.org">Dongxu Wang</a>
* @version 1.0.1.5, Apr 10, 2013
* @since 0.3.5
*/
public final class TopBars {
......@@ -107,6 +107,7 @@ public final class TopBars {
if (null == currentUser) {
topBarModel.put(Common.LOGIN_URL, userService.createLoginURL(Common.ADMIN_INDEX_URI));
topBarModel.put("loginLabel", langPropsService.get("loginLabel"));
topBarModel.put("registerLabel", langPropsService.get("registerLabel"));
topBarTemplate.process(topBarModel, stringWriter);
......
......@@ -26,6 +26,7 @@ import org.json.JSONObject;
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.2, Nov 9, 2011
* @since 0.3.1
*/
public interface ArchiveDateArticleRepository extends Repository {
......
......@@ -27,6 +27,7 @@ import org.json.JSONObject;
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.2, Jul 2, 2011
* @since 0.3.1
*/
public interface ArchiveDateRepository extends Repository {
......
......@@ -28,6 +28,7 @@ import org.json.JSONObject;
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.4, Oct 26, 2011
* @since 0.3.1
*/
public interface CommentRepository extends Repository {
......
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.b3log.solo.repository;
import org.b3log.latke.repository.Repository;
/**
* Option repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Jan 24, 2013
* @since 0.6.0
*/
public interface OptionRepository extends Repository {}
......@@ -24,5 +24,6 @@ import org.b3log.latke.repository.Repository;
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Jan 24, 2013
* @since 0.3.1
*/
public interface PluginRepository extends Repository {}
......@@ -24,5 +24,6 @@ import org.b3log.latke.repository.Repository;
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Aug 14, 2010
* @since 0.3.1
*/
public interface PreferenceRepository extends Repository {}
......@@ -24,5 +24,6 @@ import org.b3log.latke.repository.Repository;
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.1, Jan 30, 2011
* @since 0.3.1
*/
public interface StatisticRepository extends Repository {}
......@@ -27,6 +27,7 @@ import org.json.JSONObject;
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.3, Nov 8, 2011
* @since 0.3.1
*/
public interface TagArticleRepository extends Repository {
......
......@@ -27,6 +27,7 @@ import org.json.JSONObject;
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.1, Aug 12, 2010
* @since 0.3.1
*/
public interface TagRepository extends Repository {
......
......@@ -26,6 +26,7 @@ import org.json.JSONObject;
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.4, Nov 8, 2011
* @since 0.3.1
*/
public interface UserRepository extends Repository {
......
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.b3log.solo.repository.impl;
import java.util.logging.Logger;
import org.b3log.latke.repository.AbstractRepository;
import org.b3log.solo.model.Option;
import org.b3log.solo.repository.OptionRepository;
/**
* Option repository.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Apr 15, 2013
* @since 0.6.0
*/
public final class OptionRepositoryImpl extends AbstractRepository implements OptionRepository {
/**
* Logger.
*/
private static final Logger LOGGER = Logger.getLogger(OptionRepositoryImpl.class.getName());
/**
* Singleton.
*/
private static final OptionRepositoryImpl SINGLETON = new OptionRepositoryImpl(Option.OPTION);
/**
* Gets the {@link OptionRepositoryImpl1} singleton.
*
* @return the singleton
*/
public static OptionRepositoryImpl getInstance() {
return SINGLETON;
}
/**
* Private constructor.
*
* @param name the specified name
*/
private OptionRepositoryImpl(final String name) {
super(name);
}
}
......@@ -604,6 +604,46 @@ public final class ArticleMgmtService {
}
}
/**
* Increments the view count of the article specified by the given article id.
*
* @param articleId the given article id
* @throws ServiceException service exception
*/
public void incViewCount(final String articleId) throws ServiceException {
JSONObject article;
try {
article = articleRepository.get(articleId);
if (null == article) {
return;
}
} catch (final RepositoryException e) {
LOGGER.log(Level.SEVERE, "Gets article [id=" + articleId + "] failed", e);
return;
}
final Transaction transaction = articleRepository.beginTransaction();
try {
article.put(Article.ARTICLE_VIEW_COUNT, article.getInt(Article.ARTICLE_VIEW_COUNT) + 1);
articleRepository.update(articleId, article);
transaction.commit();
} catch (final Exception e) {
if (transaction.isActive()) {
transaction.rollback();
}
LOGGER.log(Level.WARNING, "Updates article view count failed");
throw new ServiceException(e);
}
}
/**
* Decrements reference count of every tag of an article specified by the
* given article id.
......@@ -713,16 +753,17 @@ public final class ArticleMgmtService {
/**
* Processes tags for article update.
*
* <ul> <li>Un-tags old article, decrements tag reference count</li>
* <li>Removes old article-tag relations</li> <li>Saves new article-tag
* relations with tag reference count</li> </ul>
* <ul>
* <li>Un-tags old article, decrements tag reference count</li>
* <li>Removes old article-tag relations</li>
* <li>Saves new article-tag relations with tag reference count</li>
* </ul>
*
* @param oldArticle the specified old article
* @param newArticle the specified new article
* @throws Exception exception
*/
private void processTagsForArticleUpdate(final JSONObject oldArticle, final JSONObject newArticle) throws Exception {
// TODO: public -> private
final String oldArticleId = oldArticle.getString(Keys.OBJECT_ID);
final List<JSONObject> oldTags = tagRepository.getByArticleId(oldArticleId);
final String tagsString = newArticle.getString(Article.ARTICLE_TAGS_REF);
......@@ -825,10 +866,11 @@ public final class ArticleMgmtService {
}
/**
* Removes tag-article relations by the specified article id and tag ids of
* the relations to be removed.
* Removes tag-article relations by the specified article id and tag ids of the relations to be removed.
*
* <p> Removes all relations if not specified the tag ids. </p>
* <p>
* Removes all relations if not specified the tag ids.
* </p>
*
* @param articleId the specified article id
* @param tagIds the specified tag ids of the relations to be removed
......
......@@ -59,7 +59,7 @@ import org.json.JSONObject;
* B3log Solo initialization service.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.1.4, Jan 18, 2013
* @version 1.0.1.5, Mar 5, 2013
* @since 0.4.0
*/
public final class InitService {
......@@ -437,6 +437,7 @@ public final class InitService {
admin.put(User.USER_NAME, requestJSONObject.getString(User.USER_NAME));
admin.put(User.USER_EMAIL, requestJSONObject.getString(User.USER_EMAIL));
admin.put(User.USER_URL, Latkes.getServePath());
admin.put(User.USER_ROLE, Role.ADMIN_ROLE);
admin.put(User.USER_PASSWORD, MD5.hash(requestJSONObject.getString(User.USER_PASSWORD)));
admin.put(UserExt.USER_ARTICLE_COUNT, 0);
......@@ -529,6 +530,7 @@ public final class InitService {
ret.put(ARTICLE_LIST_STYLE, Default.DEFAULT_ARTICLE_LIST_STYLE);
ret.put(KEY_OF_SOLO, Default.DEFAULT_KEY_OF_SOLO);
ret.put(FEED_OUTPUT_MODE, Default.DEFAULT_FEED_OUTPUT_MODE);
ret.put(FEED_OUTPUT_CNT, Default.DEFAULT_FEED_OUTPUT_CNT);
ret.put(EDITOR_TYPE, Default.DEFAULT_EDITOR_TYPE);
final String skinDirName = Default.DEFAULT_SKIN_DIR_NAME;
......
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.b3log.solo.service;
import java.util.logging.Logger;
import org.b3log.latke.Keys;
import org.b3log.latke.repository.Transaction;
import org.b3log.latke.service.ServiceException;
import org.b3log.latke.util.Strings;
import org.b3log.solo.model.Option;
import org.b3log.solo.repository.OptionRepository;
import org.b3log.solo.repository.impl.OptionRepositoryImpl;
import org.json.JSONObject;
/**
* Option management service.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Apr 16, 2013
* @since 0.6.0
*/
public final class OptionMgmtService {
/**
* Logger.
*/
private static final Logger LOGGER = Logger.getLogger(OptionMgmtService.class.getName());
/**
* Option repository.
*/
private OptionRepository optionRepository = OptionRepositoryImpl.getInstance();
/**
* Adds or updates the specified option.
*
* @param option the specified option
* @return option id
* @throws ServiceException
*/
public String addOrUpdateOption(final JSONObject option) throws ServiceException {
final Transaction transaction = optionRepository.beginTransaction();
try {
String id = option.optString(Keys.OBJECT_ID);
if (Strings.isEmptyOrNull(id)) {
id = optionRepository.add(option);
} else {
final JSONObject old = optionRepository.get(id);
if (null == old) { // The id is specified by caller
id = optionRepository.add(option);
} else {
old.put(Option.OPTION_CATEGORY, option.optString(Option.OPTION_CATEGORY));
old.put(Option.OPTION_VALUE, option.optString(Option.OPTION_VALUE));
optionRepository.update(id, old);
}
}
transaction.commit();
return id;
} catch (final Exception e) {
if (transaction.isActive()) {
transaction.rollback();
}
throw new ServiceException(e);
}
}
/**
* Removes the option specified by the given option id.
*
* @param optionId the given option id
* @throws ServiceException service exception
*/
public void removeOption(final String optionId) throws ServiceException {
final Transaction transaction = optionRepository.beginTransaction();
try {
optionRepository.remove(optionId);
transaction.commit();
} catch (final Exception e) {
if (transaction.isActive()) {
transaction.rollback();
}
throw new ServiceException(e);
}
}
/**
* Gets the {@link OptionMgmtService} singleton.
*
* @return the singleton
*/
public static OptionMgmtService getInstance() {
return OptionMgmtService.SingletonHolder.SINGLETON;
}
/**
* Private constructor.
*/
private OptionMgmtService() {}
/**
* Singleton holder.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Apr 16, 2013
*/
private static final class SingletonHolder {
/**
* Singleton.
*/
private static final OptionMgmtService SINGLETON = new OptionMgmtService();
/**
* Private default constructor.
*/
private SingletonHolder() {}
}
}
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.b3log.solo.service;
import java.util.logging.Logger;
import org.b3log.latke.Keys;
import org.b3log.latke.repository.FilterOperator;
import org.b3log.latke.repository.PropertyFilter;
import org.b3log.latke.repository.Query;
import org.b3log.latke.repository.RepositoryException;
import org.b3log.latke.service.ServiceException;
import org.b3log.solo.model.Option;
import org.b3log.solo.repository.OptionRepository;
import org.b3log.solo.repository.impl.OptionRepositoryImpl;
import org.json.JSONArray;
import org.json.JSONObject;
/**
* Option query service.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Apr 16, 2013
* @since 0.6.0
*/
public final class OptionQueryService {
/**
* Logger.
*/
private static final Logger LOGGER = Logger.getLogger(OptionQueryService.class.getName());
/**
* Option repository.
*/
private OptionRepository optionRepository = OptionRepositoryImpl.getInstance();
/**
* Gets an option with the specified option id.
*
* @param optionId the specified option id
* @return an option, returns {@code null} if not found
* @throws ServiceException service exception
*/
public JSONObject getOptionById(final String optionId) throws ServiceException {
try {
return optionRepository.get(optionId);
} catch (final RepositoryException e) {
throw new ServiceException(e);
}
}
/**
* Gets options with the specified category.
*
* <p>
* All options with the specified category will be merged into one json object as the return value.
* </p>
*
* @param category the specified category
* @return all options with the specified category, for example,
* <pre>
* {
* "${optionId}": "${optionValue}",
* ....
* }
* </pre>, returns {@code null} if not found
* @throws ServiceException service exception
*/
public JSONObject getOptions(final String category) throws ServiceException {
final Query query = new Query();
query.setFilter(new PropertyFilter(Option.OPTION_CATEGORY, FilterOperator.EQUAL, category));
try {
final JSONObject result = optionRepository.get(query);
final JSONArray options = result.getJSONArray(Keys.RESULTS);
if (0 == options.length()) {
return null;
}
final JSONObject ret = new JSONObject();
for (int i = 0; i < options.length(); i++) {
final JSONObject option = options.getJSONObject(i);
ret.put(option.getString(Keys.OBJECT_ID), option.getString(Option.OPTION_VALUE));
}
return ret;
} catch (final Exception e) {
throw new ServiceException(e);
}
}
/**
* Gets the {@link OptionQueryService} singleton.
*
* @return the singleton
*/
public static OptionQueryService getInstance() {
return OptionQueryService.SingletonHolder.SINGLETON;
}
/**
* Private constructor.
*/
private OptionQueryService() {}
/**
* Singleton holder.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Apr 16, 2013
*/
private static final class SingletonHolder {
/**
* Singleton.
*/
private static final OptionQueryService SINGLETON = new OptionQueryService();
/**
* Private default constructor.
*/
private SingletonHolder() {}
}
}
......@@ -50,7 +50,7 @@ import static org.b3log.solo.model.Preference.*;
* Preference management service.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.5, May 16, 2012
* @version 1.0.0.6, Apr 1, 2013
* @since 0.4.0
*/
public final class PreferenceMgmtService {
......@@ -180,6 +180,12 @@ public final class PreferenceMgmtService {
}
}
final String maxPageCntStr = Latkes.getMaxPageCacheCnt();
if (Integer.valueOf(maxPageCntStr) <= 0) {
preference.put(PAGE_CACHE_ENABLED, false);
}
final boolean pageCacheEnabled = preference.getBoolean(Preference.PAGE_CACHE_ENABLED);
Templates.enableCache(pageCacheEnabled);
......
......@@ -16,15 +16,29 @@
package org.b3log.solo.service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.b3log.latke.Latkes;
import org.b3log.latke.cache.PageCaches;
import org.b3log.latke.repository.RepositoryException;
import org.b3log.latke.repository.Transaction;
import org.b3log.latke.service.LangPropsService;
import org.b3log.latke.service.ServiceException;
import org.b3log.latke.util.CollectionUtils;
import org.b3log.solo.model.Article;
import org.b3log.solo.model.PageTypes;
import org.json.JSONObject;
import org.b3log.solo.model.Statistic;
import org.b3log.solo.repository.ArticleRepository;
import org.b3log.solo.repository.StatisticRepository;
import org.b3log.solo.repository.impl.ArticleRepositoryImpl;
import org.b3log.solo.repository.impl.StatisticRepositoryImpl;
import org.b3log.solo.util.Statistics;
/**
......@@ -46,6 +60,110 @@ public final class StatisticMgmtService {
*/
private StatisticRepository statisticRepository = StatisticRepositoryImpl.getInstance();
/**
* Flush size.
*/
private static final int FLUSH_SIZE = 30;
/**
* Language service.
*/
private LangPropsService langPropsService = LangPropsService.getInstance();
/**
* Article repository.
*/
private ArticleRepository articleRepository = ArticleRepositoryImpl.getInstance();
/**
* Flushes the statistic to repository.
*
* @throws ServiceException
*/
public void flushStatistic() throws ServiceException {
final JSONObject statistic = (JSONObject) statisticRepository.getCache().get(
Statistics.REPOSITORY_CACHE_KEY_PREFIX + Statistic.STATISTIC);
if (null == statistic) {
LOGGER.log(Level.INFO, "Not found statistic in cache, ignores sync");
return;
}
final Transaction transaction = statisticRepository.beginTransaction();
transaction.clearQueryCache(false);
try {
statisticRepository.getCache().remove(Statistics.REPOSITORY_CACHE_KEY_PREFIX + Statistic.STATISTIC);
// For blog view counter
statisticRepository.update(Statistic.STATISTIC, statistic);
// For article view counter
final Set<String> keys = PageCaches.getKeys();
final List<String> keyList = new ArrayList<String>(keys);
final int size = keys.size() > FLUSH_SIZE ? FLUSH_SIZE : keys.size(); // Flush FLUSH_SIZE articles at most
final List<Integer> idx = CollectionUtils.getRandomIntegers(0, keys.size(), size);
final Set<String> cachedPageKeys = new HashSet<String>();
for (final Integer i : idx) {
cachedPageKeys.add(keyList.get(i));
}
for (final String cachedPageKey : cachedPageKeys) {
final JSONObject cachedPage = PageCaches.get(cachedPageKey);
if (null == cachedPage) {
continue;
}
final Map<String, String> langs = langPropsService.getAll(Latkes.getLocale());
if (!cachedPage.optString(PageCaches.CACHED_TYPE).equals(langs.get(PageTypes.ARTICLE.getLangeLabel()))) { // Cached is not an article page
continue;
}
final int hitCount = cachedPage.optInt(PageCaches.CACHED_HIT_COUNT);
final String articleId = cachedPage.optString(PageCaches.CACHED_OID);
final JSONObject article = articleRepository.get(articleId);
if (null == article) {
continue;
}
LOGGER.log(Level.FINER, "Updating article[id={0}, title={1}] view count",
new Object[] {articleId, cachedPage.optString(PageCaches.CACHED_TITLE)});
final int oldViewCount = article.optInt(Article.ARTICLE_VIEW_COUNT);
final int viewCount = oldViewCount + hitCount;
article.put(Article.ARTICLE_VIEW_COUNT, viewCount);
article.put(Article.ARTICLE_RANDOM_DOUBLE, Math.random()); // Updates random value
articleRepository.update(articleId, article);
cachedPage.put(PageCaches.CACHED_HIT_COUNT, 0);
LOGGER.log(Level.FINER, "Updating article[id={0}, title={1}] view count from [{2}] to [{3}]",
new Object[] {articleId, article.optString(Article.ARTICLE_TITLE), oldViewCount, viewCount});
}
transaction.commit();
LOGGER.log(Level.INFO, "Synchronized statistic from cache to repository[statistic={0}]", statistic);
} catch (final RepositoryException e) {
if (transaction.isActive()) {
transaction.rollback();
}
LOGGER.log(Level.SEVERE, "Updates statistic failed", e);
}
}
/**
* Updates the statistic with the specified statistic.
*
......
......@@ -19,6 +19,7 @@ package org.b3log.solo.service;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.b3log.latke.Keys;
import org.b3log.latke.Latkes;
import org.b3log.latke.model.Role;
import org.b3log.latke.model.User;
import org.b3log.latke.repository.RepositoryException;
......@@ -26,6 +27,7 @@ import org.b3log.latke.repository.Transaction;
import org.b3log.latke.service.LangPropsService;
import org.b3log.latke.service.ServiceException;
import org.b3log.latke.util.MD5;
import org.b3log.latke.util.Strings;
import org.b3log.solo.model.UserExt;
import org.b3log.solo.repository.UserRepository;
import org.b3log.solo.repository.impl.UserRepositoryImpl;
......@@ -36,7 +38,8 @@ import org.json.JSONObject;
* User management service.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.3, Jan 4, 2013
* @author <a href="mailto:385321165@qq.com">DASHU</a>
* @version 1.0.0.4, Mar 30, 2013
* @since 0.4.0
*/
public final class UserMgmtService {
......@@ -66,7 +69,8 @@ public final class UserMgmtService {
* "userName": "",
* "userEmail": "",
* "userPassword": "", // Unhashed
* "userRole": ""
* "userRole": "", // optional
* "userURL": "", // optional
* }
* </pre>
* @throws ServiceException service exception
......@@ -98,7 +102,18 @@ public final class UserMgmtService {
oldUser.put(User.USER_EMAIL, userNewEmail);
oldUser.put(User.USER_NAME, userName);
oldUser.put(User.USER_PASSWORD, MD5.hash(userPassword));
// Unchanges the default role
final String userRole = requestJSONObject.optString(User.USER_ROLE);
if (!Strings.isEmptyOrNull(userRole)) {
oldUser.put(User.USER_ROLE, userRole);
}
final String userURL = requestJSONObject.optString(User.USER_URL);
if (!Strings.isEmptyOrNull(userURL)) {
oldUser.put(User.USER_URL, userURL);
}
userRepository.update(oldUserId, oldUser);
transaction.commit();
......@@ -112,6 +127,43 @@ public final class UserMgmtService {
}
}
/**
* Swithches the user role between "defaultRole" and "visitorRole" by the specified user id.
*
* @param userId the specified user id
* @throws ServiceException exception
* @see User
*/
public void changeRole(final String userId) throws ServiceException {
final Transaction transaction = userRepository.beginTransaction();
try {
final JSONObject oldUser = userRepository.get(userId);
if (null == oldUser) {
throw new ServiceException(langPropsService.get("updateFailLabel"));
}
final String role = oldUser.optString(User.USER_ROLE);
if (Role.VISITOR_ROLE.equals(role)) {
oldUser.put(User.USER_ROLE, Role.DEFAULT_ROLE);
} else if (Role.DEFAULT_ROLE.equals(role)) {
oldUser.put(User.USER_ROLE, Role.VISITOR_ROLE);
}
userRepository.update(userId, oldUser);
transaction.commit();
} catch (final RepositoryException e) {
if (transaction.isActive()) {
transaction.rollback();
}
LOGGER.log(Level.SEVERE, "Updates a user failed", e);
throw new ServiceException(e);
}
}
/**
* Adds a user with the specified request json object.
*
......@@ -121,8 +173,8 @@ public final class UserMgmtService {
* "userName": "",
* "userEmail": "",
* "userPassword": "", // Unhashed
* "userRole": "" // optional, uses {@value Role#DEFAULT_ROLE} instead,
* if not speciffied
* "userURL": "", // optional, uses 'servePath' instead if not specified
* "userRole": "" // optional, uses {@value Role#DEFAULT_ROLE} instead, if not speciffied
* }
* </pre>,see {@link User} for more details
* @return generated user id
......@@ -144,16 +196,32 @@ public final class UserMgmtService {
throw new ServiceException(langPropsService.get("duplicatedEmailLabel"));
}
user.put(User.USER_EMAIL, userEmail);
final String userName = requestJSONObject.optString(User.USER_NAME);
user.put(User.USER_EMAIL, userEmail);
user.put(User.USER_NAME, userName);
final String userPassword = requestJSONObject.optString(User.USER_PASSWORD);
user.put(User.USER_PASSWORD, MD5.hash(userPassword));
String userURL = requestJSONObject.optString(User.USER_URL);
if (Strings.isEmptyOrNull(userURL)) {
userURL = Latkes.getServePath();
}
if (!Strings.isURL(userURL)) {
throw new ServiceException(langPropsService.get("urlInvalidLabel"));
}
user.put(User.USER_URL, userURL);
final String roleName = requestJSONObject.optString(User.USER_ROLE, Role.DEFAULT_ROLE);
user.put(User.USER_ROLE, roleName);
user.put(UserExt.USER_ARTICLE_COUNT, 0);
user.put(UserExt.USER_PUBLISHED_ARTICLE_COUNT, 0);
......
......@@ -17,7 +17,6 @@ package org.b3log.solo.util;
import java.io.IOException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.b3log.latke.Keys;
......@@ -41,7 +40,7 @@ import org.json.JSONObject;
* Comment utilities.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.9, Mar 28, 2012
* @version 1.0.0.10, Apr 2, 2013
* @since 0.3.1
*/
public final class Comments {
......@@ -204,13 +203,7 @@ public final class Comments {
final String commentURL = requestJSONObject.optString(Comment.COMMENT_URL);
try {
new URL(commentURL);
if (commentURL.contains("<") || commentURL.contains(">")) {
throw new IllegalArgumentException();
}
} catch (final Exception e) {
if (!Strings.isURL(commentURL)) {
LOGGER.log(Level.WARNING, "Comment URL is invalid[{0}]", commentURL);
ret.put(Keys.MSG, langPropsService.get("urlInvalidLabel"));
......
......@@ -59,10 +59,10 @@ public final class Permalinks {
"/", "/article", "/tags.html", "/tags", "/page", "/blog-articles-feed.do", "/tag-articles-feed.do", "/blog-articles-rss.do",
"/tag-articles-rss.do", "/get-random-articles.do", "/article-random-double-gen.do", "/captcha.do", "/kill-browser.html",
"/add-article-comment.do", "/add-article-from-symphony-comment.do", "/add-page-comment.do", "/get-article-content", "/sitemap.xml",
"/login", "/logout", "/get-article-content", "/admin-index.do", "/admin-article.do", "/admin-article-list.do", "/admin-link-list.do",
"/admin-preference.do", "/admin-file-list.do", "/admin-page-list.do", "/admin-others.do", "/admin-draft-list.do",
"/admin-user-list.do", "/admin-plugin-list.do", "/admin-main.do", "/admin-about.do", "/admin-label", "/admin-about.do",
"/rm-all-data.do", "/init", "/clear-cache.do",
"/login", "/logout", "/forgot", "/get-article-content", "/admin-index.do", "/admin-article.do", "/admin-article-list.do",
"/admin-link-list.do", "/admin-preference.do", "/admin-file-list.do", "/admin-page-list.do", "/admin-others.do",
"/admin-draft-list.do", "/admin-user-list.do", "/admin-plugin-list.do", "/admin-main.do", "/admin-about.do", "/admin-label",
"/admin-about.do", "/rm-all-data.do", "/init", "/clear-cache.do", "/register.html"
};
/**
......
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.b3log.solo.util;
import java.util.Random;
/**
* Generate random stuff, <p> currently only support random alpha and digital
* string, whose length is also random between 8 and 16.
*
* @author <a href="mailto:dongxu.wang@acm.org">Dongxu Wang</a>
* @version 1.0.0.1, Mar 11, 2013
*/
public class Randoms {
/**
* String's length should be positive.
*/
private static final int LEN_LIM = 1;
/**
* String's length maximum limit.
*/
private static final int MAX_LEN = 16;
/**
* String's length minimum limit.
*/
private static final int MIN_LEN = 8;
/**
* String's random length.
*/
private static final int RANDOM_LEN = new Random().nextInt(MAX_LEN - MIN_LEN + LEN_LIM) + MIN_LEN;
/**
* Characters set table, can be extended.
*/
private final char[] table;
/**
* String's random seed.
*/
private final Random random = new Random();
/**
* String's random characters buffer.
*/
private final char[] buf;
/**
* Generate a random string with a random length [8, 16].
*/
public Randoms() {
this(RANDOM_LEN);
}
/**
* Generate a random string with given length.
*
* @param length string's length
*/
public Randoms(final int length) {
if (length < LEN_LIM) {
throw new IllegalArgumentException("length < 1: " + length);
}
table = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
buf = new char[length];
}
/**
* Generate next random string, whose length is also random between 8 and
* 16.
*
* @return next random string
*/
public String nextString() {
for (int idx = 0; idx < buf.length; ++idx) {
buf[idx] = table[random.nextInt(table.length)];
}
return new String(buf);
}
}
......@@ -24,7 +24,9 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.b3log.latke.Latkes;
import org.b3log.latke.repository.RepositoryException;
import org.b3log.latke.repository.Transaction;
import org.b3log.latke.util.Requests;
import org.b3log.solo.model.Statistic;
import org.b3log.solo.repository.StatisticRepository;
......@@ -41,7 +43,7 @@ import org.json.JSONObject;
* </p>
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.2.1, Dec 21, 2012
* @version 1.0.2.3, Mar 26, 2013
* @since 0.3.1
*/
public final class Statistics {
......@@ -262,8 +264,24 @@ public final class Statistics {
++blogViewCnt;
statistic.put(Statistic.STATISTIC_BLOG_VIEW_COUNT, blogViewCnt);
if (!Latkes.isDataCacheEnabled()) {
final Transaction transaction = statisticRepository.beginTransaction();
try {
statisticRepository.update(Statistic.STATISTIC, statistic);
transaction.commit();
} catch (final RepositoryException e) {
if (transaction.isActive()) {
transaction.rollback();
}
LOGGER.log(Level.SEVERE, "Updates blog view count failed", e);
}
} else {
// Repository cache prefix, Refers to GAERepository#CACHE_KEY_PREFIX
statisticRepository.getCache().putAsync(REPOSITORY_CACHE_KEY_PREFIX + Statistic.STATISTIC, statistic);
}
LOGGER.log(Level.FINER, "Inced blog view count[statistic={0}]", statistic);
}
......
......@@ -21,6 +21,7 @@ import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.b3log.latke.Keys;
import org.b3log.latke.model.Role;
import org.b3log.latke.model.User;
import org.b3log.latke.repository.Query;
import org.b3log.latke.repository.RepositoryException;
......@@ -44,7 +45,8 @@ import org.json.JSONObject;
* User utilities.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.1.3, Feb 7, 2012
* @author <a href="mailto:385321165@qq.com">DASHU</a>
* @version 1.0.1.5, Apr 1, 2013
* @since 0.3.1
*/
public final class Users {
......@@ -205,6 +207,10 @@ public final class Users {
/**
* Determines whether the specified email exits in the specified users.
*
* <p>
* If the email is a visitor's, returns {@code false}.
* </p>
*
* @param email the specified email
* @param users the specified user
* @return {@code true} if exists, {@code false} otherwise
......@@ -214,6 +220,10 @@ public final class Users {
for (int i = 0; i < users.length(); i++) {
final JSONObject user = users.getJSONObject(i);
if (isVisitor(user)) {
return false;
}
if (user.getString(User.USER_EMAIL).equalsIgnoreCase(email)) {
return true;
}
......@@ -222,6 +232,20 @@ public final class Users {
return false;
}
/**
* Check the user is visitor or not.
*
* @param user the specified user
* @return {@code true} if is visitor, {@code false} otherwise
* @throws JSONException json exception
*/
private boolean isVisitor(final JSONObject user) throws JSONException {
if (user.getString(User.USER_ROLE).equals(Role.VISITOR_ROLE)) {
return true;
}
return false;
}
/**
* Gets the {@link Users} singleton.
*
......
{
"description": "Description of repository structures, for generation (DDL: http://en.wikipedia.org/wiki/Data_Definition_Language) of the relational database table and persistence validation.",
"version": "1.0.0.7, Apr 29, 2012",
"version": "1.0.1.0, Apr 2, 2013",
"authors": ["Liang Ding"],
"since": "0.4.0",
"repositories": [
{
"name": "archiveDate",
......@@ -102,12 +101,14 @@
{
"name": "commentOriginalCommentId",
"type": "String",
"length": 255
"length": 255,
"nullable": true
},
{
"name": "commentOriginalCommentName",
"type": "String",
"length": 50
"length": 50,
"nullable": true
}
]
},
......@@ -261,6 +262,11 @@
"length": 20,
"nullable": true
},
{
"name": "feedOutputCnt",
"type": "int",
"nullable": true
},
{
"name": "articleListDisplayCount",
"type": "int",
......@@ -531,6 +537,11 @@
"type": "String",
"length": 255
},
{
"name": "userURL",
"type": "String",
"length": 255
},
{
"name": "userPassword",
"type": "String",
......@@ -643,6 +654,26 @@
"nullable": true
}
]
},
{
"name": "option",
"keys": [
{
"name": "oId",
"type": "String",
"length": 64
},
{
"name": "optionValue",
"type": "String",
"length": 512
},
{
"name": "optionCategory",
"type": "String",
"legnth": 20
}
]
}
]
}
\ No newline at end of file
......@@ -24,6 +24,7 @@ import org.b3log.solo.repository.ArchiveDateRepository;
import org.b3log.solo.repository.ArticleRepository;
import org.b3log.solo.repository.CommentRepository;
import org.b3log.solo.repository.LinkRepository;
import org.b3log.solo.repository.OptionRepository;
import org.b3log.solo.repository.PageRepository;
import org.b3log.solo.repository.PluginRepository;
import org.b3log.solo.repository.PreferenceRepository;
......@@ -36,6 +37,7 @@ import org.b3log.solo.repository.impl.ArchiveDateRepositoryImpl;
import org.b3log.solo.repository.impl.ArticleRepositoryImpl;
import org.b3log.solo.repository.impl.CommentRepositoryImpl;
import org.b3log.solo.repository.impl.LinkRepositoryImpl;
import org.b3log.solo.repository.impl.OptionRepositoryImpl;
import org.b3log.solo.repository.impl.PageRepositoryImpl;
import org.b3log.solo.repository.impl.PluginRepositoryImpl;
import org.b3log.solo.repository.impl.PreferenceRepositoryImpl;
......@@ -51,7 +53,7 @@ import org.testng.annotations.BeforeClass;
* Abstract test case.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.5, Feb 8, 2013
* @version 1.0.0.6, Apr 19, 2013
* @see #beforeClass()
* @see #afterClass()
*/
......@@ -62,119 +64,162 @@ public abstract class AbstractTestCase {
*/
private final LocalServiceTestHelper localServiceTestHelper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig());
/**
* User repository.
*/
private UserRepository userRepository;
/**
* Link repository.
*/
private LinkRepository linkRepository;
/**
* Article repository.
*/
private ArticleRepository articleRepository;
/**
* Tag repository.
*/
private TagRepository tagRepository;
/**
* Tag-Article repository.
*/
private TagArticleRepository tagArticleRepository;
/**
* Page repository.
*/
private PageRepository pageRepository;
/**
* Comment repository.
*/
private CommentRepository commentRepository;
/**
* Archive date repository.
*/
private ArchiveDateRepository archiveDateRepository;
/**
* Archive date article repository.
*/
private ArchiveDateArticleRepository archiveDateArticleRepository;
/**
* Plugin repository.
*/
private PluginRepository pluginRepository;
/**
* Preference repository.
*/
private PreferenceRepository preferenceRepository;
/**
* Statistic repository.
*/
private StatisticRepository statisticRepository;
/**
* Option repository.
*/
private OptionRepository optionRepository;
/**
* Initialization service.
*/
private InitService initService;
/**
* User management service.
*/
private UserMgmtService userMgmtService;
/**
* User query service.
*/
private UserQueryService userQueryService;
/**
* Article management service.
*/
private ArticleMgmtService articleMgmtService;
/**
* Article query service.
*/
private ArticleQueryService articleQueryService;
/**
* Page management service.
*/
private PageMgmtService pageMgmtService;
/**
* Page query service.
*/
private PageQueryService pageQueryService;
/**
* Link management service.
*/
private LinkMgmtService linkMgmtService;
/**
* Link query service.
*/
private LinkQueryService linkQueryService;
/**
* Preference management service.
*/
private PreferenceMgmtService preferenceMgmtService;
/**
* Preference query service.
*/
private PreferenceQueryService preferenceQueryService;
/**
* Tag query service.
*/
private TagQueryService tagQueryService;
/**
* Tag management service.
*/
private TagMgmtService tagMgmtService;
/**
* Comment query service.
*/
private CommentQueryService commentQueryService;
/**
* Comment management service.
*/
private CommentMgmtService commentMgmtService;
/**
* Archive date query service.
*/
private ArchiveDateQueryService archiveDateQueryService;
/**
* Option management service.
*/
private OptionMgmtService optionMgmtService;
/**
* Option query service.
*/
private OptionQueryService optionQueryService;
/**
* Before class.
*
......@@ -205,6 +250,7 @@ public abstract class AbstractTestCase {
pluginRepository = PluginRepositoryImpl.getInstance();
preferenceRepository = PreferenceRepositoryImpl.getInstance();
statisticRepository = StatisticRepositoryImpl.getInstance();
optionRepository = OptionRepositoryImpl.getInstance();
// Services
initService = InitService.getInstance();
......@@ -223,6 +269,8 @@ public abstract class AbstractTestCase {
commentQueryService = CommentQueryService.getInstance();
commentMgmtService = CommentMgmtService.getInstance();
archiveDateQueryService = ArchiveDateQueryService.getInstance();
optionMgmtService = OptionMgmtService.getInstance();
optionQueryService = OptionQueryService.getInstance();
}
/**
......@@ -235,7 +283,7 @@ public abstract class AbstractTestCase {
*/
@AfterClass
public void afterClass() {
localServiceTestHelper.tearDown();
// XXX: NPE, localServiceTestHelper.tearDown();
Latkes.shutdown();
}
......@@ -348,6 +396,15 @@ public abstract class AbstractTestCase {
return statisticRepository;
}
/**
* Gets option repository.
*
* @return option repository
*/
public OptionRepository getOptionRepository() {
return optionRepository;
}
/**
* Gets initialization service.
*
......@@ -491,4 +548,22 @@ public abstract class AbstractTestCase {
public ArchiveDateQueryService getArchiveDateQueryService() {
return archiveDateQueryService;
}
/**
* Gets option management service.
*
* @return option management service
*/
public OptionMgmtService getOptionMgmtService() {
return optionMgmtService;
}
/**
* Gets option query service.
*
* @return option query service
*/
public OptionQueryService getOptionQueryService() {
return optionQueryService;
}
}
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.b3log.solo.repository.impl;
import org.b3log.latke.Keys;
import org.b3log.latke.repository.Transaction;
import org.b3log.solo.AbstractTestCase;
import org.b3log.solo.model.Option;
import org.b3log.solo.repository.OptionRepository;
import org.json.JSONObject;
import org.testng.Assert;
import org.testng.annotations.Test;
/**
* {@link OptionRepositoryImpl} test case.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Apr 19, 2013
* @since 0.6.0
*/
@Test(suiteName = "repository")
public final class OptionRepositoryImplTestCase extends AbstractTestCase {
/**
* Tests.
*
* @throws Exception exception
*/
@Test
public void test() throws Exception {
final OptionRepository optionRepository = getOptionRepository();
final JSONObject option = new JSONObject();
option.put(Keys.OBJECT_ID, Option.ID_C_BROADCAST_CHANCE_EXPIRATION_TIME);
option.put(Option.OPTION_CATEGORY, Option.CATEGORY_C_BROADCAST);
option.put(Option.OPTION_VALUE, 0L);
Transaction transaction = optionRepository.beginTransaction();
optionRepository.add(option);
transaction.commit();
Assert.assertEquals(optionRepository.count(), 1);
Assert.assertNotNull(optionRepository.get(Option.ID_C_BROADCAST_CHANCE_EXPIRATION_TIME));
}
}
......@@ -34,7 +34,7 @@ import org.testng.annotations.Test;
* {@link UserRepositoryImpl} test case.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.1, Feb 21, 2012
* @version 1.0.0.2, Apr 2, 2013
*/
@Test(suiteName = "repository")
public final class UserRepositoryImplTestCase extends AbstractTestCase {
......@@ -52,6 +52,7 @@ public final class UserRepositoryImplTestCase extends AbstractTestCase {
another.put(User.USER_NAME, "test1");
another.put(User.USER_EMAIL, "test1@gmail.com");
another.put(User.USER_PASSWORD, "pass1");
another.put(User.USER_URL, "http://b3log.org");
another.put(User.USER_ROLE, Role.DEFAULT_ROLE);
another.put(UserExt.USER_ARTICLE_COUNT, 0);
another.put(UserExt.USER_PUBLISHED_ARTICLE_COUNT, 0);
......@@ -66,6 +67,7 @@ public final class UserRepositoryImplTestCase extends AbstractTestCase {
admin.put(User.USER_NAME, "test");
admin.put(User.USER_EMAIL, "test@gmail.com");
admin.put(User.USER_PASSWORD, "pass");
admin.put(User.USER_URL, "http://b3log.org");
admin.put(User.USER_ROLE, Role.ADMIN_ROLE);
admin.put(UserExt.USER_ARTICLE_COUNT, 0);
admin.put(UserExt.USER_PUBLISHED_ARTICLE_COUNT, 0);
......
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.b3log.solo.service;
import org.b3log.latke.Keys;
import org.b3log.solo.AbstractTestCase;
import org.b3log.solo.model.Option;
import org.json.JSONObject;
import org.testng.Assert;
import org.testng.annotations.Test;
/**
* {@link OptionMgmtService} test case.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Apr 19, 2013
* @since 0.6.0
*/
@Test(suiteName = "service")
public class OptionMgmtServiceTestCase extends AbstractTestCase {
/**
* Add.
*
* @throws Exception exception
*/
@Test
public void add() throws Exception {
final OptionMgmtService optionMgmtService = getOptionMgmtService();
final JSONObject option = new JSONObject();
option.put(Keys.OBJECT_ID, Option.ID_C_BROADCAST_CHANCE_EXPIRATION_TIME);
option.put(Option.OPTION_CATEGORY, Option.CATEGORY_C_BROADCAST);
option.put(Option.OPTION_VALUE, 0L);
final String id = optionMgmtService.addOrUpdateOption(option);
System.out.println(id);
Assert.assertNotNull(id);
}
/**
* Update.
*
* @throws Exception exception
*/
@Test
public void update() throws Exception {
final OptionMgmtService optionMgmtService = getOptionMgmtService();
JSONObject option = new JSONObject();
option.put(Keys.OBJECT_ID, Option.ID_C_BROADCAST_CHANCE_EXPIRATION_TIME);
option.put(Option.OPTION_CATEGORY, Option.CATEGORY_C_BROADCAST);
option.put(Option.OPTION_VALUE, 0L);
final String id = optionMgmtService.addOrUpdateOption(option); // Add
System.out.println(id);
Assert.assertNotNull(id);
option = new JSONObject();
option.put(Keys.OBJECT_ID, Option.ID_C_BROADCAST_CHANCE_EXPIRATION_TIME);
option.put(Option.OPTION_CATEGORY, Option.CATEGORY_C_BROADCAST);
option.put(Option.OPTION_VALUE, 1L);
optionMgmtService.addOrUpdateOption(option); // Update
final JSONObject opt = getOptionQueryService().getOptionById(Option.ID_C_BROADCAST_CHANCE_EXPIRATION_TIME);
Assert.assertEquals(opt.getInt(Option.OPTION_VALUE), 1L);
}
/**
* Remove.
*
* @throws Exception exception
*/
@Test
public void remove() throws Exception {
final OptionMgmtService optionMgmtService = getOptionMgmtService();
final JSONObject option = new JSONObject();
option.put(Keys.OBJECT_ID, Option.ID_C_BROADCAST_CHANCE_EXPIRATION_TIME);
option.put(Option.OPTION_CATEGORY, Option.CATEGORY_C_BROADCAST);
option.put(Option.OPTION_VALUE, 0L);
final String id = optionMgmtService.addOrUpdateOption(option);
Assert.assertNotNull(id);
optionMgmtService.removeOption(id);
final JSONObject opt = getOptionQueryService().getOptionById(id);
Assert.assertNull(opt);
}
}
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.b3log.solo.service;
import org.b3log.latke.Keys;
import org.b3log.latke.util.Requests;
import org.b3log.solo.AbstractTestCase;
import org.b3log.solo.model.Link;
import org.b3log.solo.model.Option;
import org.json.JSONObject;
import org.testng.Assert;
import org.testng.annotations.Test;
/**
* {@link OptionQueryService} test case.
*
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.0, Apr 19, 2013
* @since 0.6.0
*/
@Test(suiteName = "service")
public class OptionQueryServiceTestCase extends AbstractTestCase {
/**
* Gets.
*
* @throws Exception exception
*/
@Test
public void get() throws Exception {
// Check
final OptionQueryService optionQueryService = getOptionQueryService();
JSONObject options = optionQueryService.getOptions(Option.CATEGORY_C_BROADCAST);
Assert.assertNull(options);
// Add one
final OptionMgmtService optionMgmtService = getOptionMgmtService();
final JSONObject option = new JSONObject();
option.put(Keys.OBJECT_ID, Option.ID_C_BROADCAST_CHANCE_EXPIRATION_TIME);
option.put(Option.OPTION_CATEGORY, Option.CATEGORY_C_BROADCAST);
option.put(Option.OPTION_VALUE, 0L);
final String id = optionMgmtService.addOrUpdateOption(option);
Assert.assertNotNull(id);
// Check again
options = optionQueryService.getOptions(Option.CATEGORY_C_BROADCAST);
Assert.assertNotNull(options);
}
}
#
# Copyright (C) 2009, 2010, 2011, B3log Team
# Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
......@@ -15,13 +15,10 @@
#
#
# Description: timeline skin.
# Version: 1.0.0.1, Jan 7, 2013
# Author: Liyuan Li
# Description: B3log configurations for testing.
# Version: 1.0.0.0, Apr 19, 2013
# Author: Liang Ding
#
name=timeline
version=1.0.1
forSolo=0.5.6
memo=\u65f6\u5149\u6d41\u901d
note=\u6b64\u76ae\u80a4\u5ffd\u7565\u66f4\u65b0\u3001\u7f6e\u9876\u6392\u5e8f
rhythm.servePath=http://localhost:8081
symphony.servePath=http://localhost:8084
......@@ -16,7 +16,7 @@
#
# Description: B3log Latke configurations for test (GAE runtime).
# Version: 1.0.0.1, May 2, 2012
# Version: 1.0.0.2, Apr 1, 2013
# Author: Liang Ding
#
......@@ -51,5 +51,9 @@ cache=GAE
# userService=GAE
userService=LOCAL
#### Cache ####
cache.maxPageCnt=128
cache.maxDataCnt=128
#### Static resource version ####
staticResourceVersion=201206280945
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!--
Description: B3log Solo parent POM.
Version: 2.0.2.8, Feb 8, 2013
Version: 2.0.2.9, Mar 12, 2013
Author: Liang Ding
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
......@@ -11,7 +11,7 @@
<groupId>org.b3log</groupId>
<artifactId>solo</artifactId>
<packaging>pom</packaging>
<version>0.5.6</version>
<version>0.6.0</version>
<name>B3log Solo</name>
<url>https://github.com/b3log/b3log-solo</url>
<description>
......@@ -28,13 +28,13 @@
<!-- Properties -->
<properties>
<servlet.version>2.5</servlet.version>
<org.b3log.solo.version>0.5.6</org.b3log.solo.version>
<org.b3log.solo.version>0.6.0</org.b3log.solo.version>
<org.b3log.latke.version>0.5.0-SNAPSHOT</org.b3log.latke.version>
<org.b3log.latke-gae.version>0.5.0-SNAPSHOT</org.b3log.latke-gae.version>
<org.b3log.latke-bae.version>0.5.0-SNAPSHOT</org.b3log.latke-bae.version>
<org.b3log.latke-repository-mysql.version>0.5.0-SNAPSHOT</org.b3log.latke-repository-mysql.version>
<org.b3log.latke-repository-h2.version>0.5.0-SNAPSHOT</org.b3log.latke-repository-h2.version>
<gae.version>1.7.2</gae.version>
<gae.version>1.7.7</gae.version>
<freemarker-gae.version>2.3.19</freemarker-gae.version>
<jsoup.version>1.5.2</jsoup.version>
......@@ -327,10 +327,34 @@
<ignore></ignore>
</action>
</pluginExecution>
<pluginExecution>
<pluginExecutionFilter>
<groupId>
com.tiobe.jacobe
</groupId>
<artifactId>
maven-jacobe-plugin
</artifactId>
<versionRange>
[1.0,)
</versionRange>
<goals>
<goal>jacobe</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
......
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
<?xml version="1.0" encoding="UTF-8"?>
<!--
Description: B3log Solo BAE POM.
Version: 1.0.1.2, Jan 15, 2013
Version: 1.0.1.3, Mar 8, 2013
Author: Liang Ding
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
......@@ -19,7 +19,7 @@
<parent>
<groupId>org.b3log</groupId>
<artifactId>solo-war</artifactId>
<version>0.5.6</version>
<version>0.6.0</version>
</parent>
<properties>
......@@ -50,6 +50,12 @@
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
</exclusion>
<!-- H2 database for local -->
<exclusion>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</exclusion>
</exclusions>
</dependency>
......
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="web" name="Web">
<configuration>
<descriptors>
<deploymentDescriptor name="context.xml" url="file://$MODULE_DIR$/../src/main/webapp/META-INF/context.xml" />
<deploymentDescriptor name="web.xml" url="file://$MODULE_DIR$/../src/main/webapp/WEB-INF/web.xml" />
</descriptors>
<webroots>
<root url="file://$MODULE_DIR$/../src/main/webapp" relative="/" />
</webroots>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: org.b3log:latke:0.5.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: org.freemarker:freemarker:2.3.19" level="project" />
<orderEntry type="library" name="Maven: commons-io:commons-io:1.4" level="project" />
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.5" level="project" />
<orderEntry type="library" name="Maven: javassist:javassist:3.12.1.GA" level="project" />
<orderEntry type="library" name="Maven: javax.servlet:servlet-api:2.5" level="project" />
<orderEntry type="library" name="Maven: org.b3log:latke-bae:0.5.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: org.b3log:latke-repository-mysql:0.5.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-simple:1.5.10" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.5.10" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.testng:testng:6.1.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:3.8.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.beanshell:bsh:2.0b4" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: com.beust:jcommander:1.12" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.yaml:snakeyaml:1.6" level="project" />
<orderEntry type="module" module-name="solo-core" />
<orderEntry type="library" name="Maven: org.jsoup:jsoup:1.5.2" level="project" />
<orderEntry type="library" name="Maven: org.tautua.markdownpapers:markdownpapers-core:1.3.2" level="project" />
</component>
</module>
......@@ -16,7 +16,7 @@
#
# Description: B3log Latke configurations. Configures the section "Server" carefully.
# Version: 1.0.0.7, Sep 7, 2012
# Version: 1.0.0.8, Apr 1, 2013
# Author: Liang Ding
#
......@@ -48,5 +48,9 @@ cache=BAE
#### User Service Implementation ####
userService=LOCAL
#### Cache ####
cache.maxPageCnt=128
cache.maxDataCnt=128
#### Static resource version ####
staticResourceVersion=201211021410
\ No newline at end of file
......@@ -18,7 +18,7 @@
# Description: B3log Solo local environment configurations. Configures this file
# if B3log Solo runs on a standard Servlet container or Baidu App Engine,
# it is unnecessary to care this file if B3log Solo runs on Google App Engine.
# Version: 1.0.2.2, Jan 23, 2013
# Version: 1.0.2.3, Apr 1, 2013
# Author: Liang Ding
#
......@@ -44,7 +44,3 @@ jdbc.transactionIsolation=READ_COMMITTED
# The specific table name prefix
jdbc.tablePrefix=b3_solo
#### Cache ####
cache.maxPageCnt=128
cache.maxDataCnt=128
\ No newline at end of file
......@@ -19,12 +19,14 @@
<parent>
<groupId>org.b3log</groupId>
<artifactId>solo-war</artifactId>
<version>0.5.6</version>
<version>0.6.0</version>
</parent>
<properties>
<maven-gae-plugin.version>0.9.4</maven-gae-plugin.version>
<maven-gae-plugin.version>0.9.5</maven-gae-plugin.version>
<gae.dev_sever.port>8080</gae.dev_sever.port>
<webappDirectory>${project.build.directory}/${project.build.finalName}</webappDirectory>
<gae.home>${settings.localRepository}/com/google/appengine/appengine-java-sdk/${gae.version}/appengine-java-sdk-${gae.version}</gae.home>
</properties>
<dependencies>
......@@ -117,8 +119,9 @@
<version>${maven-gae-plugin.version}</version>
<configuration>
<serverId>appengine.google.com</serverId>
<sdkDir>${settings.localRepository}/com/google/appengine/appengine-java-sdk/${gae.version}/appengine-java-sdk-${gae.version}</sdkDir>
<appDir>${project.build.directory}/${project.build.finalName}</appDir>
<unpackVersion>${gae.version}</unpackVersion>
<appDir>${webappDirectory}</appDir>
<sdkDir>${gae.home}</sdkDir>
<port>${gae.dev_sever.port}</port>
<passIn>true</passIn>
<!-- TODO: http://code.google.com/p/googleappengine/issues/detail?id=6928#c7 -->
......
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="web" name="Web">
<configuration>
<webroots>
<root url="file://$MODULE_DIR$/src/main/webapp" relative="/" />
</webroots>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
......@@ -16,7 +16,7 @@
#
# Description: B3log Latke configurations. Configures the section "Server" carefully.
# Version: 1.0.0.6, Aug 14, 2012
# Version: 1.0.0.7, Apr 1, 2013
# Author: Liang Ding
#
......@@ -47,5 +47,9 @@ cache=GAE
#### User Service Implementation ####
userService=LOCAL
#### Cache ####
cache.maxPageCnt=1024000
cache.maxDataCnt=1024000
#### Static resource version ####
staticResourceVersion=201211021410
\ No newline at end of file
......@@ -19,7 +19,7 @@
<parent>
<groupId>org.b3log</groupId>
<artifactId>solo-war</artifactId>
<version>0.5.6</version>
<version>0.6.0</version>
</parent>
<properties>
......
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="web" name="Web">
<configuration>
<descriptors>
<deploymentDescriptor name="context.xml" url="file://$MODULE_DIR$/../src/main/webapp/META-INF/context.xml" />
<deploymentDescriptor name="web.xml" url="file://$MODULE_DIR$/../src/main/webapp/WEB-INF/web.xml" />
</descriptors>
<webroots>
<root url="file://$MODULE_DIR$/../src/main/webapp" relative="/" />
</webroots>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: org.b3log:latke:0.5.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: org.freemarker:freemarker:2.3.19" level="project" />
<orderEntry type="library" name="Maven: javax.mail:mail:1.4" level="project" />
<orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
<orderEntry type="library" name="Maven: commons-io:commons-io:1.4" level="project" />
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.5" level="project" />
<orderEntry type="library" name="Maven: javassist:javassist:3.12.1.GA" level="project" />
<orderEntry type="library" name="Maven: com.h2database:h2:1.3.170" level="project" />
<orderEntry type="library" name="Maven: org.jboss:jboss-vfs:3.1.0.Final" level="project" />
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.0.0.CR1" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: javax.servlet:servlet-api:2.5" level="project" />
<orderEntry type="module" module-name="solo-core" />
<orderEntry type="library" name="Maven: org.jsoup:jsoup:1.5.2" level="project" />
<orderEntry type="library" name="Maven: org.tautua.markdownpapers:markdownpapers-core:1.3.2" level="project" />
<orderEntry type="library" name="Maven: org.b3log:latke-repository-h2:0.5.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-simple:1.5.10" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.5.10" level="project" />
</component>
</module>
......@@ -16,7 +16,7 @@
#
# Description: B3log Latke configurations. Configures the section "Server" carefully.
# Version: 1.0.0.6, Aug 14, 2012
# Version: 1.0.0.7, Apr 1, 2013
# Author: Liang Ding
#
......@@ -47,5 +47,9 @@ cache=LOCAL
#### User Service Implementation ####
userService=LOCAL
#### Cache ####
cache.maxPageCnt=128
cache.maxDataCnt=128
#### Static resource version ####
staticResourceVersion=201211021410
\ No newline at end of file
......@@ -18,7 +18,7 @@
# Description: B3log Solo local environment configurations. Configures this file
# if B3log Solo runs on a standard Servlet container or Baidu App Engine,
# it is unnecessary to care this file if B3log Solo runs on Google App Engine.
# Version: 1.0.2.3, Jan 23, 2013
# Version: 1.0.2.4, Apr 1, 2013
# Author: Liang Ding
#
......@@ -42,8 +42,5 @@ jdbc.maxConnCnt=10
jdbc.transactionIsolation=READ_COMMITTED
# The specific table name prefix
jdbc.tablePrefix=b3_solo
jdbc.tablePrefix=
#### Cache ####
cache.maxPageCnt=128
cache.maxDataCnt=128
......@@ -19,7 +19,7 @@
<parent>
<groupId>org.b3log</groupId>
<artifactId>solo-war</artifactId>
<version>0.5.6</version>
<version>0.6.0</version>
</parent>
<properties>
......
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="web" name="Web">
<configuration>
<webroots>
<root url="file://$MODULE_DIR$/src/main/webapp" relative="/" />
</webroots>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
......@@ -16,7 +16,7 @@
#
# Description: B3log Latke configurations. Configures the section "Server" carefully.
# Version: 1.0.0.6, Aug 14, 2012
# Version: 1.0.0.7, Apr 1, 2013
# Author: Liang Ding
#
......@@ -47,5 +47,9 @@ cache=LOCAL
#### User Service Implementation ####
userService=LOCAL
#### Cache ####
cache.maxPageCnt=128
cache.maxDataCnt=128
#### Static resource version ####
staticResourceVersion=201211021410
\ No newline at end of file
......@@ -18,7 +18,7 @@
# Description: B3log Solo local environment configurations. Configures this file
# if B3log Solo runs on a standard Servlet container or Baidu App Engine,
# it is unnecessary to care this file if B3log Solo runs on Google App Engine.
# Version: 1.0.2.2, Jan 23, 2013
# Version: 1.0.2.4, Apr 1, 2013
# Author: Liang Ding
#
......@@ -33,8 +33,8 @@ jdbc.password=
# database connection pool
# Note: If the runtime environment is BAE, the pool will be 'none' always
jdbc.pool=BoneCP
#jdbc.pool=c3p0
#jdbc.pool=BoneCP
jdbc.pool=c3p0
# The minConnCnt MUST larger or equal to 3
jdbc.minConnCnt=3
......@@ -45,7 +45,3 @@ jdbc.transactionIsolation=READ_COMMITTED
# The specific table name prefix
jdbc.tablePrefix=
#### Cache ####
cache.maxPageCnt=128
cache.maxDataCnt=128
......@@ -19,7 +19,7 @@
<parent>
<groupId>org.b3log</groupId>
<artifactId>solo</artifactId>
<version>0.5.6</version>
<version>0.6.0</version>
</parent>
<modules>
......
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="web" name="Web">
<configuration>
<descriptors>
<deploymentDescriptor name="web.xml" url="file://$MODULE_DIR$/src/main/webapp/WEB-INF/web.xml" />
</descriptors>
<webroots>
<root url="file://$MODULE_DIR$/src/main/webapp" relative="/" />
</webroots>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="solo-core" />
<orderEntry type="library" name="Maven: org.b3log:latke:0.5.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: org.freemarker:freemarker:2.3.19" level="project" />
<orderEntry type="library" name="Maven: javax.mail:mail:1.4" level="project" />
<orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
<orderEntry type="library" name="Maven: commons-io:commons-io:1.4" level="project" />
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.5" level="project" />
<orderEntry type="library" name="Maven: javassist:javassist:3.12.1.GA" level="project" />
<orderEntry type="library" name="Maven: com.jolbox:bonecp:0.7.1.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.google.guava:guava:r08" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.5.10" level="project" />
<orderEntry type="library" name="Maven: c3p0:c3p0:0.9.1.2" level="project" />
<orderEntry type="library" name="Maven: com.h2database:h2:1.3.170" level="project" />
<orderEntry type="library" name="Maven: org.jboss:jboss-vfs:3.1.0.Final" level="project" />
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.0.0.CR1" level="project" />
<orderEntry type="library" name="Maven: org.jsoup:jsoup:1.5.2" level="project" />
<orderEntry type="library" name="Maven: org.tautua.markdownpapers:markdownpapers-core:1.3.2" level="project" />
</component>
</module>
#
# Copyright (c) 2009, 2010, 2011, 2012, 2013, B3log Team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
# Description: B3log configurations.
# Version: 1.0.0.0, Apr 19, 2013
# Author: Liang Ding
#
rhythm.servePath=http://rhythm.b3log.org:80
symphony.servePath=http://symphony.b3log.org:80
......@@ -16,13 +16,13 @@
#
# Description: B3log Solo language configurations(en_US).
# Version: 2.1.0.2, Jan 29, 2013
# Version: 2.1.0.8, Apr 14, 2013
# Author: Liang Ding
# Author: Liyuan Li
# Author: Dongxu Wang
#
staticErrorLabel=<h1>staticServePath Error</h1><a target='_blank' href='https://github.com/b3log/b3log-solo/wiki/usr_faq'>https://github.com/b3log/b3log-solo/wiki/usr_faq</a>
staticErrorLabel=<h1>staticServePath Error</h1><a target='_blank' href='https://github.com/b3log/b3log-solo/wiki/usr_faq#1-init'>https://github.com/b3log/b3log-solo/wiki/usr_faq</a>
markdownHelpLabel=<dl><dt>Headings</dt><dd> # First-level heading</dd><dd> #### Fourth-level heading</dd></dl>\
<dl><dt>Link</dt><dd>[link text here](link.address.here)</dd></dl>\
<dl><dt>Emphasized text</dt><dd>*italics* or _italics_</dd><dd>**boldface** or __boldface__</dd><dd>***boldface+italics*** or ___boldface+italics___</dd></dl>\
......@@ -66,6 +66,7 @@ commentListLabel=Comments
draftListLabel=Drafts
userManageLabel=Users
commonUserLabel=Common User
visitorUserLabel=visitor
addUserLabel=Add User
updateUserLabel=Update User
linkManagementLabel=Links
......@@ -82,6 +83,7 @@ preferenceLabel=Preference
localeString1Label=Language:
timeZoneId1Label=Time Zone:
adminLabel=Admin
roleLabel=Role
administratorLabel=Administrator
loginLabel=Login
loginFailLabel=Login Fail :-(
......@@ -144,6 +146,7 @@ yearLabel=
monthLabel=
pageLabel=Page
navMgmtLabel=Navigation
navLabel=Navigation
openMethod1Label=Target:
openMethodLabel=Target
linkEmptyLabel=Link is empty
......@@ -188,7 +191,11 @@ importLabel=Import
chooseBlog1Label=Choose Blog:
blogArticleImportLabel=Article Import
userName1Label=Username:
userLabel=User
userPassword1Label=Password:
userPasswordLabel=Password
userURL1Label=Link:
userURLLabel=Link
categoryLabel=Category
noticeBoard1Label=Notice Board:
noticeBoardLabel=Notice Board
......@@ -250,6 +257,12 @@ goTopLabel=Top
permalink1Label=Permalink:
permalinkLabel=Permalink
welcomeToSoloLabel=Welcome to
forgotLabel=forgot password
sendLabel=Send
userEmailNotFoundMsg=Sorry, email not found.
resetPwdSuccessMsg=A new random password has been sent to your mail. For the sake of security, however, please update your password after login using it within next 24 hours.
resetPwdMailSubject=[B3log Solo]Random Password
resetPwdMailBody=Please use the random password to login within 24 hours and reset, the password is:
initIntroLabel= <p>Please click "Initial" button to initialize your blog ;-)</br></br>\
Welcome to the <a href="http://symphony.b3log.org" target="_blank">B3log Symphony community</a> of <b>Equality \u2022 Freedom \u2022 Passion</b> at the same time.</br></br>\
<span style="font-size:12px"><span style="color:red">Note</span>: Only to ensure Email is the same and <a href="/article/1353772377257" target="_blank">synchronization configured</a> is correctly,\
......@@ -263,6 +276,8 @@ enableArticleUpdateHint1Label=Enable Article Update Hint:
allowVisitDraftViaPermalink1Label=Allow Visit Draft Via Link:
allowComment1Label=Allow Comment:
feedOutputModel1Label=Feed Output Mode:
feedOutputCntLabel=Feed Output Count
feedOutputCnt1Label=Feed Output Count:
abstractLabel=Abstract
fullContentLabel=Full Content
author1Label=Author:
......@@ -336,10 +351,13 @@ duplicatedPermalinkLabel=Duplicated permalink!
invalidPermalinkFormatLabel=Invalid permalink format!
duplicatedEmailLabel=Duplicated email!
refreshAndRetryLabel=Please refresh and try again!
editorLeaveLabel=Content is not null, Do you leave\uff1f
editorPostLabel=Content is not null, Do you clear\uff1f
editorLeaveLabel=Content is not null, Do you leave?
editorPostLabel=Content is not null, Do you clear?
registerSoloUserLabel=Register Solo User
registerLabel=Register
changeRoleLabel=Change Role
####
confirmRemoveLabel=Are You Sure?
confirmRemoveLabel=Are You Remove
confirmInitLabel=Are You Sure?
###### Common ######
b3logLabel=<span style="color: orange;">B</span><span style="color: blue;"><sup>3</sup></span><span style="color: green;">L</span><span style="color: red;">O</span><span style="color: blue;">G</span>
......
......@@ -16,13 +16,13 @@
#
# Description: B3log Solo default language configurations(zh_CN).
# Version: 2.1.0.9, Jan 29, 2013
# Version: 2.1.1.5, Apr 14, 2013
# Author: Liang Ding
# Author: Liyuan Li
# Author: Dongxu Wang
#
staticErrorLabel=<h1>staticServePath \u914d\u7f6e\u9519\u8bef</h1>\u8bf7\u67e5\u770b <a target='_blank' href='https://github.com/b3log/b3log-solo/wiki/usr_faq'>https://github.com/b3log/b3log-solo/wiki/usr_faq</a>
staticErrorLabel=<h1>staticServePath \u914d\u7f6e\u9519\u8bef</h1>\u8bf7\u67e5\u770b <a target='_blank' href='https://github.com/b3log/b3log-solo/wiki/usr_faq#1-init'>https://github.com/b3log/b3log-solo/wiki/usr_faq</a>
markdownHelpLabel=<dl><dt>\u6807\u9898</dt><dd> # \u4e00\u7ea7\u6807\u9898</dd><dd> #### \u56db\u7ea7\u6807\u9898</dd></dl>\
<dl><dt>\u94fe\u63a5</dt><dd>[\u94fe\u63a5\u6587\u5b57](\u94fe\u63a5\u5730\u5740)</dd></dl>\
<dl><dt>\u5f3a\u8c03</dt><dd>*\u659c\u4f53* \u6216\u8005 _\u659c\u4f53_</dd><dd>**\u7c97\u4f53** \u6216\u8005 __\u7c97\u4f53__</dd><dd>***\u7c97\u4f53+\u659c\u4f53*** \u6216\u8005 ___\u7c97\u4f53+\u659c\u4f53___</dd></dl>\
......@@ -66,6 +66,7 @@ commentListLabel=\u8bc4\u8bba\u7ba1\u7406
draftListLabel=\u8349\u7a3f\u5939
userManageLabel=\u7528\u6237\u7ba1\u7406
commonUserLabel=\u4e00\u822c\u7528\u6237
visitorUserLabel=\u8bbf\u5ba2\u7528\u6237
addUserLabel=\u6dfb\u52a0\u7528\u6237
updateUserLabel=\u66f4\u65b0\u7528\u6237
linkManagementLabel=\u94fe\u63a5\u7ba1\u7406
......@@ -82,6 +83,7 @@ preferenceLabel=\u504f\u597d\u8bbe\u5b9a
localeString1Label=\u8bed\u8a00\uff1a
timeZoneId1Label=\u65f6\u533a\uff1a
adminLabel=\u7ba1\u7406
roleLabel=\u89d2\u8272
administratorLabel=\u7ba1\u7406\u5458
loginLabel=\u767b\u5f55
loginFailLabel=\u767b\u5f55\u5931\u8d25 :-(
......@@ -144,6 +146,7 @@ yearLabel=\u5e74
monthLabel=\u6708
pageLabel=\u9875\u9762
navMgmtLabel=\u5bfc\u822a\u7ba1\u7406
navLabel=\u5bfc\u822a
openMethod1Label=\u9875\u9762\u6253\u5f00\u65b9\u5f0f\uff1a
openMethodLabel=\u9875\u9762\u6253\u5f00\u65b9\u5f0f
linkEmptyLabel=\u94fe\u63a5\u4e0d\u80fd\u4e3a\u7a7a
......@@ -188,7 +191,11 @@ importLabel=\u5bfc\u5165
chooseBlog1Label=\u8bf7\u9009\u62e9\u9700\u8981\u7ba1\u7406\u7684\u535a\u5ba2\uff1a
blogArticleImportLabel=\u6587\u7ae0\u5bfc\u5165
userName1Label=\u7528\u6237\u540d\uff1a
userLabel=\u7528\u6237
userPassword1Label=\u5bc6\u7801\uff1a
userPasswordLabel=\u5bc6\u7801
userURL1Label=\u94fe\u63a5\uff1a
userURLLabel=\u94fe\u63a5
categoryLabel=\u5206\u7c7b
noticeBoard1Label=\u516c\u544a\uff1a
noticeBoardLabel=\u516c\u544a
......@@ -250,9 +257,16 @@ goTopLabel=\u9876\u90e8
permalink1Label=\u94fe\u63a5\uff1a
permalinkLabel=\u94fe\u63a5
welcomeToSoloLabel=\u6b22\u8fce\u4f7f\u7528
forgotLabel=\u5fd8\u8bb0\u5bc6\u7801
sendLabel=\u53d1\u9001
userEmailNotFoundMsg=\u90ae\u7bb1\u5730\u5740\u6709\u8bef\uff0c\u8bf7\u91cd\u8bd5
resetPwdSuccessMsg=\u4e00\u4e2a\u65b0\u7684\u968f\u673a\u5bc6\u7801\u5df2\u7ecf\u53d1\u9001\u5230\u4f60\u7684\u6ce8\u518c\u90ae\u7bb1,\u8bf7\u4e8e24\u5c0f\u65f6\u5185\u4f7f\u7528\u8be5\u5bc6\u7801\u767b\u9646\uff0c\u5b89\u5168\u8d77\u89c1\uff0c\u8bf7\u767b\u9646\u540e\u4fee\u6539\u5bc6\u7801
resetPwdMailSubject=[B3log Solo]\u968f\u673a\u5bc6\u7801
resetPwdMailBody=\u8bf7\u4f7f\u7528\u968f\u673a\u751f\u6210\u7684\u5bc6\u7801\u572824\u5c0f\u65f6\u5185\u767b\u9646\u5e76\u4fee\u6539\u5bc6\u7801\uff0c\u65b0\u7684\u968f\u673a\u5bc6\u7801\u4e3a\uff1a
initIntroLabel=<p>\u8bf7\u70b9\u51fb\u4e0b\u9762\u7684\u201c\u521d\u59cb\u5316\u201d\u6309\u94ae\u8fdb\u884c\u521d\u59cb\u5316\uff0c\u7136\u540e\u7a0d\u7b49\u7247\u523b ;-)</br></br></br></br>\
\u540c\u65f6\uff0c\u6b22\u8fce\u60a8\u52a0\u5165<b>\u5e73\u7b49\u2022\u81ea\u7531\u2022\u5954\u653e</b>\u7684 <a href="http://symphony.b3log.org" target="_blank">B3log Symphony \u793e\u533a</a>\u3002</br></br>\
<span style="font-size:12px"><span style="color:red">\u6ce8</span>\uff1a\u5f53\u6ce8\u518c Email \u4e0e B3log Solo \u4fdd\u6301\u4e00\u81f4\uff0c\u5e76\u4e14\u793e\u533a\u4e2d\u7684<a href="http://symphony.b3log.org/article/1353772377257" target="_blank">\u540c\u6b65\u8bbe\u7f6e</a>\u914d\u7f6e\u6b63\u786e\u65f6\uff0c\u60a8\u7684\u6587\u7ae0\u548c\u8bc4\u8bba\u5c31\u53ef\u5728\u793e\u533a\u548c\u4e2a\u4eba\u535a\u5ba2\u4e2d\u4fdd\u6301<i>\u53cc\u5411\u540c\u6b65</i>\u3002</span></p>
<span style="font-size:12px"><span style="color:red">\u6ce8</span>\uff1a\u5f53\u6ce8\u518c Email \u4e0e B3log Solo \u4fdd\u6301\u4e00\u81f4\uff0c\u5e76\u4e14\u793e\u533a\u4e2d\u7684<a href="http://symphony.b3log.org/article/1353772377257" target="_blank">\u540c\u6b65\u8bbe\u7f6e</a>\u914d\u7f6e\u6b63\u786e\u65f6\uff0c\
\u60a8\u7684\u6587\u7ae0\u548c\u8bc4\u8bba\u5c31\u53ef\u5728\u793e\u533a\u548c\u4e2a\u4eba\u535a\u5ba2\u4e2d\u4fdd\u6301<i>\u53cc\u5411\u540c\u6b65</i>\u3002</span></p>
killBrowserLabel=<h2>\u8ba9\u6211\u4eec\u653e\u5f03\u4f7f\u7528\u90a3\u4e9b\u8fc7\u65f6\u3001\u4e0d\u5b89\u5168\u7684\u6d4f\u89c8\u5668\u5427\uff01</h2><p>\u4e3a\u4e86\u8ba9\u6d4f\u89c8\u5668\u66f4\u597d\u7684\u53d1\u5c55\uff0c\u4eba\u7c7b\u66f4\u52a0\u7684\u8fdb\u6b65\uff0c\u62e5\u6709\u66f4\u597d\u7684\u4f53\u9a8c\uff0c\u8ba9\u6211\u4eec\u653e\u5f03\u4f7f\u7528\u90a3\u4e9b\u8fc7\u65f6\u3001\u4e0d\u5b89\u5168\u7684\u6d4f\u89c8\u5668\u3002</p>\u60a8\u53ef\u4ee5\u4e0b\u8f7d<ul><li><a href="http://www.mozilla.com/" target="_blank">\u706b\u72d0</a></li><li><a href="http://www.google.com/chrome" target="_blank">\u8c37\u6b4c\u6d4f\u89c8\u5668</a></li><li><a href="http://windows.microsoft.com/en-US/internet-explorer/downloads/ie" target="_blank">IE8 / IE9</a></li><li><a href="http://www.maxthon.com/" target="_blank">\u9068\u6e38</a>\u6216\u8005<a href="http://www.google.com" target="_blank">\u5176\u5b83\u6d4f\u89c8\u5668</a>.</li></ul><span style="font-size: 10px">\u6ce8\uff1a\u5220\u9664 /js/common.js \u4e2d\u7684 Util.killIE(); \u53ef\u5bf9\u6240\u6709\u6d4f\u89c8\u5668\u8fdb\u884c\u652f\u6301\u3002</span>
readmoreLabel=\u9605\u8bfb\u66f4\u591a\u00bb
readmore2Label=\u9605\u8bfb\u66f4\u591a
......@@ -262,6 +276,8 @@ enableArticleUpdateHint1Label=\u542f\u7528\u6587\u7ae0\u66f4\u65b0\u63d0\u793a\u
allowVisitDraftViaPermalink1Label=\u5141\u8bb8\u901a\u8fc7\u94fe\u63a5\u8bbf\u95ee\u8349\u7a3f\uff1a
allowComment1Label=\u5141\u8bb8\u8bc4\u8bba\uff1a
feedOutputModel1Label=\u8ba2\u9605\u8f93\u51fa\u6a21\u5f0f\uff1a
feedOutputCntLabel=\u8ba2\u9605\u8f93\u51fa\u6587\u7ae0\u6570
feedOutputCnt1Label=\u8ba2\u9605\u8f93\u51fa\u6587\u7ae0\u6570\uff1a
abstractLabel=\u6458\u8981
fullContentLabel=\u5168\u6587
author1Label=\u4f5c\u8005\uff1a
......@@ -337,8 +353,11 @@ duplicatedEmailLabel=\u90ae\u4ef6\u5730\u5740\u91cd\u590d\uff01
refreshAndRetryLabel=\u8bf7\u5237\u65b0\u91cd\u8bd5\uff01
editorLeaveLabel=\u7f16\u8f91\u5668\u4e2d\u8fd8\u6709\u5185\u5bb9\uff0c\u662f\u5426\u79bb\u5f00\uff1f
editorPostLabel=\u7f16\u8f91\u5668\u4e2d\u8fd8\u6709\u5185\u5bb9\uff0c\u662f\u5426\u6e05\u7a7a\uff1f
registerSoloUserLabel=\u6ce8\u518c Solo \u7528\u6237
registerLabel=\u6ce8\u518c
changeRoleLabel=\u6539\u53d8\u89d2\u8272
####
confirmRemoveLabel=\u786e\u5b9a\u5220\u9664\uff1f
confirmRemoveLabel=\u662f\u5426\u5220\u9664
confirmInitLabel=\u786e\u5b9a\u8fdb\u884c\u521d\u59cb\u5316\u5417\uff1f
###### Common ######
b3logLabel=<span style="color: orange;">B</span><span style="color: blue;"><sup>3</sup></span><span style="color: green;">L</span><span style="color: red;">O</span><span style="color: blue;">G</span>
......
......@@ -5,10 +5,27 @@
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<h2>Release 0.5.6 - Feb 19, 2013</h2>
<h2>Release 0.6.0 - Apr 26, 2013</h2>
<ul>
<li><a href="https://github.com/b3log/b3log-solo/issues/199">199 社区文章更新接口</a>&nbsp;<span style='background: #02e10c !important;color:#FFFFFF !important;padding: 1px 4px;'>feature</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/203">203 用户注册,实现多用户博客</a>&nbsp;<span style='background: #02e10c !important;color:#FFFFFF !important;padding: 1px 4px;'>feature</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/226">226 加入字典存储 option</a>&nbsp;<span style='background: #e102d8 !important;color:#FFFFFF !important;padding: 1px 4px;'>development</span>&nbsp;<span style='background: #02e10c !important;color:#FFFFFF !important;padding: 1px 4px;'>feature</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/198">198 删除文章出错</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/205">205 禁用缓存后文章浏览计数不变</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/214">214 Zoundry Raven 发布问题</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/144">144 KindEditor 上传问题</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/193">193 登录后再访问登录页将跳转后台</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/194">194 删除操作提示改进</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/195">195 去除草稿夹浏览按钮</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/196">196 清除缓存丢失访问统计</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/202">202 自定义 Feed 文章数</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/210">210 升级至 GAE 1.7.7</a>&nbsp;<span style='background: #e102d8 !important;color:#FFFFFF !important;padding: 1px 4px;'>development</span></li>
</ul>
<h2>Release 0.5.6 - Feb 19, 2012</h2>
<ul>
<li><a href="https://github.com/b3log/b3log-solo/issues/130">130 登录用户评论时无需输入验证码</a>&nbsp;<span style='background: #84b6eb !important;color:#FFFFFF !important;padding: 1px 4px;'>enhancement</span>&nbsp;<span style='background: #02e10c !important;color:#FFFFFF !important;padding: 1px 4px;'>feature</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/150">150 支持 H2 数据库</a>&nbsp;<span style='background: #02e10c !important;color:#FFFFFF !important;padding: 1px 4px;'>feature</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/171">171 新皮肤 timeline</a>&nbsp;<span style='background: #02e10c !important;color:#FFFFFF !important;padding: 1px 4px;'>feature</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/133">133 前端代理后在线人数不正常</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/141">141 请求 Latke Remote APIs 时跳过初始化检查</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
<li><a href="https://github.com/b3log/b3log-solo/issues/142">142 保存为草稿后再发布无法同步</a>&nbsp;<span style='background: #fc2929 !important;color:#FFFFFF !important;padding: 1px 4px;'>bug</span></li>
......@@ -418,5 +435,4 @@
<li><a href="http://code.google.com/p/b3log-solo/issues/detail?id=2">2 Tree-House 皮肤评论预览有问题</a></li>
</ul>
</body>
</html>
......@@ -20,12 +20,12 @@
Description: Web deployment descriptor on GAE. See
http://code.google.com/intl/en/appengine/docs/java/config/appconfig.html
for more details.
Version: 1.0.3.11, Feb 4, 2013
Version: 1.0.4.2, Apr 26, 2013
Author: Liang Ding
-->
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>solo-demo</application>
<version>056</version>
<version>060</version>
<sessions-enabled>true</sessions-enabled>
......
......@@ -44,7 +44,7 @@
<input type="checkbox" id="articleCommentable" checked="checked" /> &nbsp; &nbsp; &nbsp;
<span id="postToCommunityPanel">
<label for="postToCommunity">
<a class="no-underline" href="http://symphony.b3log.org/usage" target="_blank">${postToCommunityLabel}</a>
<a class="no-underline" href="http://symphony.b3log.org/article/1360294444788" target="_blank">${postToCommunityLabel}</a>
</label>
<input id="postToCommunity" type="checkbox" checked="checked"/>
</span>
......
......@@ -54,6 +54,7 @@
"versionLabel": "${versionLabel}",
"commentNameLabel": "${commentNameLabel}",
"commentEmailLabel": "${commentEmailLabel}",
"roleLabel": "${roleLabel}",
"administratorLabel": "${administratorLabel}",
"duplicatedEmailLabel": "${duplicatedEmailLabel}",
"mailInvalidLabel": "${mailInvalidLabel}",
......@@ -110,7 +111,11 @@
"randomArticlesDisplayCntLabel": "${randomArticlesDisplayCntLabel}",
"relevantArticlesDisplayCntLabel": "${relevantArticlesDisplayCntLabel}",
"externalRelevantArticlesDisplayCntLabel": "${externalRelevantArticlesDisplayCntLabel}",
"nameTooLongLabel": "${nameTooLongLabel}"
"nameTooLongLabel": "${nameTooLongLabel}",
"navLabel": "${navLabel}",
"userLabel": "${userLabel}",
"changeRoleLabel": "${changeRoleLabel}",
"visitorUserLabel": "${visitorUserLabel}"
};
admin.init();
......
......@@ -277,6 +277,14 @@
</select>
</td>
</tr>
<tr>
<th>
<label for="feedOutputCnt">${feedOutputCnt1Label}</label>
</th>
<td>
<input id="feedOutputCnt" class="normalInput" type="text"/>
</td>
</tr>
<tr>
<th colspan="2">
......
......@@ -26,6 +26,14 @@
<input id="userEmail" type="text"/>
</td>
</tr>
<tr>
<th>
<label for="userURL">${userURL1Label}</label>
</th>
<td>
<input id="userURL" type="text"/>
</td>
</tr>
<tr>
<th>
<label for="userPassword">${userPassword1Label}</label>
......@@ -67,6 +75,14 @@
<input id="userEmailUpdate" type="text"/>
</td>
</tr>
<tr>
<th>
<label for="userURLUpdate">${userURL1Label}</label>
</th>
<td>
<input id="userURLUpdate" type="text"/>
</td>
</tr>
<tr>
<th>
<label for="userPasswordUpdate">${userPassword1Label}</label>
......
......@@ -5,8 +5,9 @@
<title>${articleViewPwdLabel}</title>
<meta name="keywords" content="GAE 博客,GAE blog,b3log" />
<meta name="description" content="An open source blog based on GAE Java,GAE Java 开源博客" />
<meta name="owner" content="B3log Team" />
<meta name="author" content="B3log Team" />
<meta name="generator" content="B3log" />
<meta name="generator" content="B3log Solo" />
<meta name="copyright" content="B3log" />
<meta name="revised" content="B3log, ${year}" />
<meta name="robots" content="noindex, follow" />
......
......@@ -18,57 +18,99 @@
* 403, 404, 500, article-pwd, init, login and kill-browser page style.
*
* @author <a href="mailto:LLY219@gmail.com">Liyuan Li</a>
* @version 1.0.1.2, Aug 27, 2012
* @version 1.0.1.4, Apr 2, 2013
*/
html {
height: 100%;
overflow: hidden;
}
*,html,body {
html,body {
margin: 0;
padding: 0;
}
body {
background-color: #F3F1E5;
color: #4D505D;
color: #333;
font-family: \5fae\8f6f\96c5\9ed1;
font-size: small;
height: 100%;
}
button {
background: url(../images/icon.png) repeat center bottom;
border: 1px solid;
border-color: #CCC #BBBBBB #A0A0A0;
border-radius: 4px;
height: 28px;
h2 {
background-color:#ECECEC;
background-image:linear-gradient(#F9F9F9, #ECECEC);
background-repeat:repeat-x;
border-radius: 4px 4px 0 0;
font-size: 16px;
margin: 0;
padding: 0 6px;
vertical-align: top;
float: right;
margin: 12px 0 0 24px;
outline: none;
padding: 10px 20px;
text-shadow: 0 -1px 0 rgba(255, 255, 255, 0.5);
}
input {
background: none repeat scroll 0 0 #FBFBFB;
border: 1px solid #E5E5E5;
box-shadow: 1px 1px 2px rgba(200, 200, 200, 0.2) inset;
color: #4D505D;
font-family: Helvetica,Arial,'sans-serif','\5fae\8f6f\96c5\9ed1';
font-size: 20px;
font-weight: 200;
height: 28px;
margin-top: 10px;
outline: medium none;
padding: 3px;
width: 280px;
border: 1px solid #CCCCCC;
border-radius: 3px 3px 3px 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075) inset;
font-size: 13px;
margin: 15px 0;
padding: 7px 8px;
transition: all 0.15s ease-in 0s;
vertical-align: middle;
width: 410px;
}
input:focus {
box-shadow: 0px 0px 5px rgba(200, 200, 200, 0.9);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075) inset, 0 0 5px rgbargba(200, 200, 200, 0.9);
border: 1px solid #E6E5D9;
}
.form {
padding: 20px;
}
label {
font-size: 13px;
}
button {
position:relative;
display:inline-block;
font-size:13px;
font-weight:700;
color:#333;
text-shadow:0 1px 0 rgba(255,255,255,0.9);
white-space:nowrap;
background-color:#eaeaea;
background-image:linear-gradient(#fafafa,#eaeaea);
background-repeat:repeat-x;
border-radius:3px;
border:1px solid #ddd;
border-bottom-color:#c5c5c5;
box-shadow:0 1px 3px rgba(0,0,0,0.075);
vertical-align:baseline;
cursor:pointer;
-webkit-touch-callout:none;
-webkit-user-select:none;
-khtml-user-select:none;
-moz-user-select:none;
-ms-user-select:none;
user-select:none;
-webkit-appearance:none;
outline:none;
padding:7px 15px;
margin-top: 10px;
}
button:hover,
button:active {
color:#fff;
text-decoration:none;
text-shadow:0 -1px 0 rgba(0,0,0,0.25);
background-color: #3072b3;
background-image:linear-gradient(#599bcd,#3072b3);
background-repeat:repeat-x;
}
.clear {
......@@ -86,7 +128,7 @@ input:focus {
display: none;
}
.icon {
.main .icon {
position: absolute;
right: 0px;
top: 0px;
......@@ -141,22 +183,10 @@ input:focus {
text-decoration: none;
}
.main ul {
margin-bottom: 73px;
}
.main li {
margin: 6px 0 6px 16px;
}
.main p {
margin: 12px 0;
}
.mian tr {
height: 54px;
}
.footerWrapper {
background-color: #FFFFFF;
border-top: 1px solid #E6E5D9;
......@@ -172,16 +202,17 @@ input:focus {
}
/* start article-pwd */
.article-pwd > div,
.article-pwd > form {
margin: 0 20px;
}
.article-pwd > div {
margin-bottom: 10px;
max-height: 264px;
overflow: auto;
word-wrap: break-word;
}
.article-pwd #confirm {
margin-top: 6px;
}
/* end article-pwd */
/* start 403/404/500 */
......@@ -197,11 +228,11 @@ input:focus {
}
.a-403 {
margin: 20px 75px 0 0 ;
margin: 10px 75px 0 0 ;
}
.img-500 {
margin: 25px 0 0 25px;
margin: 20px 0 0 25px;
}
.a-500 {
......@@ -209,39 +240,58 @@ input:focus {
}
/* end 403/404/500 */
/* start login */
.login table {
margin: 66px auto;
}
/* end login */
/* start kill */
.kill {
.kill img {
position: absolute;
right: 40px;
top: 230px;
top: 200px;
}
.kill ul {
margin-bottom: 50px;
}
.kill p {
margin: 12px 20px;
}
.kill span {
margin-left: 20px;
}
/* end kill */
/* start init and login */
/* start init */
#init {
position: absolute;
top: 102px;
top: 81px;
width: 470px;
}
#init input,
.register input {
margin: 5px 0;
padding: 5px 8px;
}
.register {
height: 400px;
}
#sys p {
height: 166px;
}
#sys {
padding: 0 20px;
}
#initButton {
margin-right: 10px;
}
#tip {
color: #21759B;
float: right;
font-weight: bold;
margin-top: 18px;
margin-left: 10px;
}
/* end init and login */
/* end init */
html{height:100%;overflow:hidden}*,html,body{margin:0;padding:0}body{background-color:#f3f1e5;color:#4d505d;font-family:\5fae\8f6f\96c5\9ed1;font-size:small;height:100%}button{background:url(../images/icon.png) repeat center bottom;border:1px solid;border-color:#CCc #bbb #A0A0A0;border-radius:4px;height:28px;margin:0;padding:0 6px;vertical-align:top;float:right;margin:12px 0 0 24px;outline:0}input{background:none repeat scroll 0 0 #fbfbfb;border:1px solid #e5e5e5;box-shadow:1px 1px 2px rgba(200,200,200,0.2) inset;color:#4d505d;font-family:Helvetica,Arial,'sans-serif','\5fae\8f6f\96c5\9ed1';font-size:20px;font-weight:200;height:28px;margin-top:10px;outline:medium none;padding:3px;width:280px}input:focus{box-shadow:0 0 5px rgba(200,200,200,0.9)}.clear{background-color:transparent;border:0;clear:both;display:block;font-size:0;height:0;line-height:0;overflow:hidden}.none{display:none}.icon{position:absolute;right:0;top:0;width:16px;height:16px}.solo{color:orangered;font-weight:bold}.logo{float:left;padding:162px 12px 0;width:153px}.wrapper{height:auto;min-height:100%;position:relative}.wrap{border-top:5px solid #e6e5d9;min-height:400px}.content{background:url("../images/zz.jpg") repeat-x scroll center bottom white;border-color:#e6e5d9;border-style:solid solid none;border-width:1px;margin:0 auto;position:relative;width:700px;top:60px}.main{border-left:1px solid #e6e5d9;float:right;font-size:15px;margin:24px 0;padding:12px 24px;width:470px;height:338px}.main a{text-decoration:none}.main ul{margin-bottom:73px}.main li{margin:6px 0 6px 16px}.main p{margin:12px 0}.mian tr{height:54px}.footerWrapper{background-color:#fff;border-top:1px solid #e6e5d9;bottom:0;padding:12px 0;position:absolute;text-align:center;width:100%}.footerWrapper a{text-decoration:none}.article-pwd>div{margin-bottom:10px;max-height:264px;overflow:auto;word-wrap:break-word}.article-pwd #confirm{margin-top:6px}.img-403,.img-500{box-shadow:0 0 5px #e6e5d9;margin:20px 0 0 45px;padding:5px}.a-403,.a-500{margin:20px 50px 0 0;text-align:right}.a-403{margin:20px 75px 0 0}.img-500{margin:25px 0 0 25px}.a-500{margin:25px 35px 0 0}.login table{margin:66px auto}.kill{position:absolute;right:40px;top:230px}#init{position:absolute;top:102px;width:470px}#sys p{height:166px}#initButton{margin-right:10px}#tip{color:#21759b;float:right;font-weight:bold;margin-top:18px}
\ No newline at end of file
html{height:100%;overflow:hidden}html,body{margin:0;padding:0}body{background-color:#f3f1e5;color:#333;font-family:\5fae\8f6f\96c5\9ed1;font-size:small;height:100%}h2{background-color:#ececec;background-image:linear-gradient(#f9f9f9,#ececec);background-repeat:repeat-x;border-radius:4px 4px 0 0;font-size:16px;margin:0;padding:10px 20px;text-shadow:0 -1px 0 rgba(255,255,255,0.5)}input{border:1px solid #ccc;border-radius:3px 3px 3px 3px;box-shadow:0 1px 2px rgba(0,0,0,0.075) inset;font-size:13px;margin:15px 0;padding:7px 8px;transition:all .15s ease-in 0s;vertical-align:middle;width:410px}input:focus{box-shadow:0 1px 2px rgba(0,0,0,0.075) inset,0 0 5px rgbargba(200,200,200,0.9);border:1px solid #e6e5d9}.form{padding:20px}label{font-size:13px}button{position:relative;display:inline-block;font-size:13px;font-weight:700;color:#333;text-shadow:0 1px 0 rgba(255,255,255,0.9);white-space:nowrap;background-color:#eaeaea;background-image:linear-gradient(#fafafa,#eaeaea);background-repeat:repeat-x;border-radius:3px;border:1px solid #ddd;border-bottom-color:#c5c5c5;box-shadow:0 1px 3px rgba(0,0,0,0.075);vertical-align:baseline;cursor:pointer;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-appearance:none;outline:0;padding:7px 15px;margin-top:10px}button:hover,button:active{color:#fff;text-decoration:none;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#3072b3;background-image:linear-gradient(#599bcd,#3072b3);background-repeat:repeat-x}.clear{background-color:transparent;border:0;clear:both;display:block;font-size:0;height:0;line-height:0;overflow:hidden}.none{display:none}.main .icon{position:absolute;right:0;top:0;width:16px;height:16px}.solo{color:orangered;font-weight:bold}.logo{float:left;padding:162px 12px 0;width:153px}.wrapper{height:auto;min-height:100%;position:relative}.wrap{border-top:5px solid #e6e5d9;min-height:400px}.content{background:url("../images/zz.jpg") repeat-x scroll center bottom white;border-color:#e6e5d9;border-style:solid solid none;border-width:1px;margin:0 auto;position:relative;width:700px;top:60px}.main{border-left:1px solid #e6e5d9;float:right;font-size:15px;margin:24px 0;padding:12px 24px;width:470px;height:338px}.main a{text-decoration:none}.main li{margin:6px 0 6px 16px}.footerWrapper{background-color:#fff;border-top:1px solid #e6e5d9;bottom:0;padding:12px 0;position:absolute;text-align:center;width:100%}.footerWrapper a{text-decoration:none}.article-pwd>div,.article-pwd>form{margin:0 20px}.article-pwd>div{margin-bottom:10px;max-height:264px;overflow:auto;word-wrap:break-word}.img-403,.img-500{box-shadow:0 0 5px #e6e5d9;margin:20px 0 0 45px;padding:5px}.a-403,.a-500{margin:20px 50px 0 0;text-align:right}.a-403{margin:10px 75px 0 0}.img-500{margin:20px 0 0 25px}.a-500{margin:25px 35px 0 0}.kill img{position:absolute;right:40px;top:200px}.kill ul{margin-bottom:50px}.kill p{margin:12px 20px}.kill span{margin-left:20px}#init{position:absolute;top:81px;width:470px}#init input,.register input{margin:5px 0;padding:5px 8px}.register{height:400px}#sys p{height:166px}#sys{padding:0 20px}#initButton{margin-right:10px}#tip{color:#21759b;font-weight:bold;margin-left:10px}
\ No newline at end of file
This diff is collapsed.
......@@ -18,7 +18,7 @@
*
* @author <a href="mailto:LLY219@gmail.com">Liyuan Li</a>
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.3.0, Jan 29, 2013
* @version 1.0.3.1, Feb 23, 2013
*/
admin.article = {
// 当发文章,取消发布,更新文章时设置为 false。不需在离开编辑器时进行提示。
......@@ -98,9 +98,10 @@ admin.article = {
* 删除文章
* @id 文章 id
* @fromId 文章来自草稿夹(draft)/文件夹(article)
* @title 文章标题
*/
del: function (id, fromId) {
var isDelete = confirm(Label.confirmRemoveLabel);
del: function (id, fromId, title) {
var isDelete = confirm(Label.confirmRemoveLabel + Label.articleLabel + '"' + title + '"?');
if (isDelete) {
$("#loadMsg").text(Label.loadingLabel);
$("#tipMsg").text("");
......
......@@ -18,7 +18,7 @@
*
* @author <a href="mailto:LLY219@gmail.com">Liyuan Li</a>
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.1.3, Jan 30, 2013
* @version 1.0.1.4, Feb 23, 2013
*/
/* article-list 相关操作 */
......@@ -93,7 +93,7 @@ admin.articleList = {
var topClass = articles[i].articlePutTop ? Label.cancelPutTopLabel : Label.putTopLabel;
articleData[i].expendRow = "<a target='_blank' href='" + latkeConfig.servePath + articles[i].articlePermalink + "'>" + Label.viewLabel + "</a> \
<a href='javascript:void(0)' onclick=\"admin.article.get('" + articles[i].oId + "', true)\">" + Label.updateLabel + "</a> \
<a href='javascript:void(0)' onclick=\"admin.article.del('" + articles[i].oId + "', 'article')\">" + Label.removeLabel + "</a> \
<a href='javascript:void(0)' onclick=\"admin.article.del('" + articles[i].oId + "', 'article', '" + articles[i].articleTitle + "')\">" + Label.removeLabel + "</a> \
<a href='javascript:void(0)' onclick=\"admin.articleList.popTop(this, '" + articles[i].oId + "')\">" + topClass + "</a> \
<a href='javascript:void(0)' onclick=\"admin.comment.open('" + articles[i].oId + "', 'article')\">" + Label.commentLabel + "</a>";
}
......
......@@ -18,7 +18,7 @@
*
* @author <a href="mailto:LLY219@gmail.com">Liyuan Li</a>
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.0.7, May 3, 2012
* @version 1.0.0.8, Feb 23, 2013
*/
admin.comment = {
......@@ -97,9 +97,10 @@ admin.comment = {
* 删除评论
* @id 评论 id
* @fromId 该评论来自文章/草稿/自定义页面
* @articleId 该评论对应的实体 id,可能是文章,也可能是自定义页面
*/
del: function (id, fromId, articleId) {
var isDelete = confirm(Label.confirmRemoveLabel);
var isDelete = confirm(Label.confirmRemoveLabel + Label.commentLabel + "?");
if (isDelete) {
$("#loadMsg").text(Label.loadingLabel);
var from = "article";
......
......@@ -18,7 +18,7 @@
*
* @author <a href="mailto:LLY219@gmail.com">Liyuan Li</a>
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.1.4, May 4, 2012
* @version 1.0.1.5, Feb 23, 2013
*/
/* comment-list 相关操作 */
......@@ -118,7 +118,7 @@ admin.commentList = {
* @type 评论类型:文章/自定义页面
*/
del: function (id, type) {
if (confirm(Label.confirmRemoveLabel)) {
if (confirm(Label.confirmRemoveLabel + Label.commentLabel + "?")) {
$("#loadMsg").text(Label.loadingLabel);
$.ajax({
......
......@@ -18,7 +18,7 @@
*
* @author <a href="mailto:LLY219@gmail.com">Liyuan Li</a>
* @author <a href="mailto:DL88250@gmail.com">Liang Ding</a>
* @version 1.0.1.3, May 4, 2012
* @version 1.0.1.4, Feb 23, 2013
*/
/* draft-list 相关操作 */
......@@ -91,9 +91,8 @@ admin.draftList = {
articleData[i].title = "<a class='no-underline' href='" + latkeConfig.servePath +
articles[i].articlePermalink + "' target='_blank'>" +
articles[i].articleTitle + "</a><span class='table-tag'>" + articles[i].articleTags + "</span>";
articleData[i].expendRow = "<a target='_blank' href='" + latkeConfig.servePath + articles[i].articlePermalink + "'>" + Label.viewLabel + "</a> \
<a href='javascript:void(0)' onclick=\"admin.article.get('" + articles[i].oId + "', false);\">" + Label.updateLabel + "</a> \
<a href='javascript:void(0)' onclick=\"admin.article.del('" + articles[i].oId + "', 'draft')\">" + Label.removeLabel + "</a> \
articleData[i].expendRow = "<a href='javascript:void(0)' onclick=\"admin.article.get('" + articles[i].oId + "', false);\">" + Label.updateLabel + "</a> \
<a href='javascript:void(0)' onclick=\"admin.article.del('" + articles[i].oId + "', 'draft', '" + articles[i].articleTitle + "')\">" + Label.removeLabel + "</a> \
<a href='javascript:void(0)' onclick=\"admin.comment.open('" + articles[i].oId + "', 'draft')\">" + Label.commentLabel + "</a>";
}
......
......@@ -15,6 +15,8 @@
*/
/**
* @fileoverview KindEditor
* @description 修改点:plugins/image/image.js 注释 173-176
* plugins/media/media.js 注释 26 & 28
*
* @author <a href="mailto:LLY219@gmail.com">Liyuan Li</a>
* @version 1.0.0.2, Jun 19, 2012
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment