@Async protected void notifyUsers(Topic topic, TopicReply reply, String cnt, int userId) { String replyAuthorName = dao.fetch(User.class, userId).getName(); // 通知原本的作者 if (topic.getUserId() != userId) { String alert = replyAuthorName + "回复了您的帖子"; pushUser( topic.getUserId(), alert, topic.getId(), replyAuthorName, topic.getTitle(), PushService.PUSH_TYPE_REPLY); } Set<String> ats = findAt(cnt, 5); for (String at : ats) { User user = dao.fetch(User.class, at); if (user == null) continue; if (topic.getUserId() == user.getId()) continue; // 前面已经发过了 if (userId == user.getId()) continue; // 自己@自己, 忽略 String alert = replyAuthorName + "在帖子回复中@了你"; pushUser( user.getId(), alert, topic.getId(), replyAuthorName, topic.getTitle(), PushService.PUSH_TYPE_AT); } }
@At("/passwd/reset") public void resetPassword(String email, HttpServletRequest req) { if (Strings.isBlank(email)) return; User user = dao.fetch(User.class, Cnd.where("email", "=", email)); if (user == null) return; dao.clear(PasswordReset.class, Cnd.where("uid", "=", user.getId())); String token = R.UU64() + R.UU64(); PasswordReset reset = new PasswordReset(); reset.setUid(dao.fetch(User.class, Cnd.where("email", "=", email)).getId()); reset.setToken(token); dao.insert(reset); String url = req.getRequestURL() + "/callback?token=" + token; mailService.add2Queue(email, "推爸 密码重置请求", "Reset URL --> " + url); }
@Filters(@By(type = AjaxCheckSession.class, args = "me")) @At("/update") public Object updateInfo( String nickName, String passwd, @Attr("me") User me, HttpSession session) { if (!Strings.isBlank(nickName) && !nickName.startsWith("_") // 系统默认生成的nickName以_开头 && me.getNickName().startsWith("_") // 只允许修改一次nickName && nickName.trim().length() > 1 && nickName.trim().length() < 10 && nickName.indexOf("<") < 0 && nickName.indexOf(">") < 0 && nickName.indexOf("@") < 0 && nickName.indexOf("#") < 0 && nickName.indexOf(" ") < 0 && nickName.indexOf("&") < 0) { try { dao.update( User.class, Chain.make("nickName", nickName.trim()), Cnd.where("id", "=", me.getId())); } catch (Throwable e) { return Ajax.fail().setMsg("Nickname is dup or it is BAD!"); } } if (!Strings.isBlank(passwd) && passwd.trim().length() > 5 && passwd.trim().length() < 40) { dao.update( User.class, Chain.make("passwd", xMD5(passwd.trim())), Cnd.where("id", "=", me.getId())); } session.setAttribute("me", dao.fetch(User.class, Cnd.where("id", "=", me.getId()))); return Ajax.ok(); }
@Aop("redis") public boolean updateTags(String topicId, @Param("tags") Set<String> tags) { if (Strings.isBlank(topicId) || tags == null) { return false; } Topic topic = dao.fetch(Topic.class, topicId); if (topic == null) return false; Set<String> oldTags = topic.getTags(); if (oldTags == null) oldTags = new HashSet<>(); log.debugf("update from '%s' to '%s'", oldTags, tags); topic.setTags(tags); dao.update(topic, "tags"); Set<String> newTags = new HashSet<>(tags); newTags.removeAll(oldTags); Set<String> removeTags = new HashSet<>(oldTags); ; removeTags.remove(tags); fillTopic(topic, null); Date lastReplyTime = topic.getCreateTime(); if (topic.getLastComment() != null) lastReplyTime = topic.getLastComment().getCreateTime(); Pipeline pipe = jedis().pipelined(); for (String tag : removeTags) { pipe.zrem(RKEY_TOPIC_TAG + tag.toLowerCase().trim(), topic.getId()); pipe.zincrby(RKEY_TOPIC_TAG_COUNT, -1, tag.toLowerCase().trim()); } for (String tag : newTags) { pipe.zadd(RKEY_TOPIC_TAG + tag.toLowerCase().trim(), lastReplyTime.getTime(), topic.getId()); pipe.zincrby(RKEY_TOPIC_TAG_COUNT, 1, tag.toLowerCase().trim()); } pipe.sync(); return true; }
@At("/passwd/reset/callback") public Object resetPasswdCallback(String token) { PasswordReset reset = dao.fetch(PasswordReset.class, Cnd.where("token", "=", token)); if (reset != null) { dao.clear(PasswordReset.class, Cnd.where("token", "=", token)); if (System.currentTimeMillis() - reset.getCreateTime().getTime() > 30 * 60 * 1000) return Ajax.fail().setMsg("token is expise"); String passwd = R.sg(12).next(); dao.update( User.class, Chain.make("passwd", xMD5(passwd)), Cnd.where("id", "=", reset.getUid())); String email = dao.fetch(User.class, Cnd.where("id", "=", reset.getUid())).getEmail(); mailService.add2Queue(email, "推爸密码重置邮件", "Your password : "******"Reset success!! Check you email!"); } return Ajax.fail().setMsg("Token not found!!"); }
public List<Topic> getRecentReplyTopics(int userId, Pager pager) { Map<Integer, UserProfile> authors = new HashMap<Integer, UserProfile>(); Cnd cnd = Cnd.where("userId", "=", userId); cnd.desc("createTime"); Sql sql = Sqls.queryString("select DISTINCT topicId from t_topic_reply $cnd") .setEntity(dao.getEntity(TopicReply.class)) .setVar("cnd", cnd); pager.setRecordCount( dao.execute( Sqls.fetchInt("select count(DISTINCT topicId) from t_topic_reply $cnd") .setEntity(dao.getEntity(TopicReply.class)) .setVar("cnd", cnd)) .getInt()); sql.setPager(pager); String[] replies_topic_ids = dao.execute(sql).getObject(String[].class); List<Topic> recent_replies = new ArrayList<Topic>(); for (String topic_id : replies_topic_ids) { Topic _topic = dao.fetch(Topic.class, topic_id); if (_topic == null) continue; recent_replies.add(_topic); } if (!recent_replies.isEmpty()) { for (Topic topic : recent_replies) { fillTopic(topic, authors); } } return recent_replies; }
@At @Ok("json") @AdaptBy(type = JsonAdaptor.class) public Object del( @Param("..") Store store, @Attr(scope = Scope.SESSION, value = "account") Account acc) { dao.delete(dao.fetch(Store.class, store.getId())); return store; }
@Aop("redis") public CResult add(Topic topic, int userId) { if (userId < 1) { return _fail("请先登录"); } if (Strings.isBlank(topic.getTitle()) || topic.getTitle().length() > 1024 || topic.getTitle().length() < 5) { return _fail("标题长度不合法"); } if (Strings.isBlank(topic.getContent())) { return _fail("内容不合法"); } if (topic.getTags() != null && topic.getTags().size() > 10) { return _fail("最多只能有10个tag"); } if (0 != dao.count(Topic.class, Cnd.where("title", "=", topic.getTitle().trim()))) { return _fail("相同标题已经发过了"); } topic.setTitle(Strings.escapeHtml(topic.getTitle().trim())); topic.setUserId(userId); topic.setTop(false); topic.setTags(new HashSet<String>()); if (topic.getType() == null) topic.setType(TopicType.ask); topic.setContent(Toolkit.filteContent(topic.getContent())); String oldContent = topic.getContent(); topic.setContentId(bigContentService.put(topic.getContent())); topic.setContent(null); dao.insert(topic); try { topic.setContent(oldContent); topicSearchService.add(topic); } catch (Exception e) { } // 如果是ask类型,把帖子加入到 "未回复"列表 Pipeline pipe = jedis().pipelined(); if (TopicType.ask.equals(topic.getType())) { pipe.zadd(RKEY_TOPIC_NOREPLY, System.currentTimeMillis(), topic.getId()); } pipe.zadd(RKEY_TOPIC_UPDATE + topic.getType(), System.currentTimeMillis(), topic.getId()); if (topic.getType() != TopicType.shortit) pipe.zadd(RKEY_TOPIC_UPDATE_ALL, System.currentTimeMillis(), topic.getId()); pipe.zincrby(RKEY_USER_SCORE, 100, "" + userId); pipe.sync(); String replyAuthorName = dao.fetch(User.class, userId).getName(); for (Integer watcherId : globalWatcherIds) { if (watcherId != userId) pushUser( watcherId, "新帖:" + topic.getTitle(), topic.getId(), replyAuthorName, topic.getTitle(), PushService.PUSH_TYPE_REPLY); } updateTopicTypeCount(); return _ok(topic.getId()); }
@At public Object login(String email, String passwd, HttpServletRequest req) { if (Strings.isBlank(email) || Strings.isBlank(passwd)) return Ajax.fail(); User me = dao.fetch(User.class, Cnd.where("email", "=", email).and("passwd", "=", xMD5(passwd))); if (me == null) return Ajax.fail(); req.getSession().setAttribute("me", me); return Ajax.ok(); }
protected UserProfile _cacheFetch(Map<Integer, UserProfile> authors, int userId) { if (authors == null) return null; UserProfile author = authors.get(userId); if (author == null) { author = dao.fetch(UserProfile.class, userId); authors.put(userId, author); } return author; }
@Aop("redis") public Object check(String topicId, int replies) { Topic topic = dao.fetch(Topic.class, topicId); if (topic == null) return ""; Double reply_count = jedis().zscore(RKEY_REPLY_COUNT, topicId); if (reply_count == null) reply_count = Double.valueOf(0); if (reply_count.intValue() == replies) { return ""; } String replyId = jedis().hget(RKEY_REPLY_LAST, topicId); TopicReply reply = dao.fetch(TopicReply.class, replyId); dao.fetchLinks(reply, null); NutMap re = new NutMap().setv("count", reply_count.intValue()); re.put("data", reply.getAuthor().getNickname() + " 回复了帖子:" + topic.getTitle()); re.put("options", new NutMap().setv("tag", topicId)); return re; }
@Override public List<Item> listSameItems(long itemId) { Item item = dao.fetch(Item.class, itemId); if (null == item) { throw new AppRuntimeException("木有找到该item"); } return dao.query( Item.class, Cnd.where("oid", "=", item.getOid()).and("skuMoreId", "=", item.getSkuMoreId())); }
public void init() { if (topicGlobalWatchers != null) { for (String username : Strings.splitIgnoreBlank(topicGlobalWatchers)) { User user = dao.fetch(User.class, username); if (user == null) { log.infof("no such user[name=%s] for topic watch", username); continue; } globalWatcherIds.add(user.getId()); } } }
@Override public Item findWithOrder(long id) { if (id <= 0) { throw new IllegalParameterException(); } Item item = dao.fetch(Item.class, id); if (null != item) { dao.fetchLinks(item, "order"); } return item; }
@Aop("redis") public List<Topic> fetchTop() { List<Topic> list = new ArrayList<>(); Map<Integer, UserProfile> authors = new HashMap<>(); for (String id : jedis().zrevrangeByScore(RKEY_TOPIC_TOP, Long.MAX_VALUE, 0)) { Topic topic = dao.fetch(Topic.class, id); if (topic == null) continue; fillTopic(topic, authors); list.add(topic); } return list; }
// @RequiresPermissions("topic:index:rebuild") public void rebuild() throws IOException { Sql sql = Sqls.queryString("select id from t_topic where tp='ask'"); dao.execute(sql); luceneIndex.writer.deleteAll(); String[] topicIds = sql.getObject(String[].class); for (String topicId : topicIds) { Topic topic = dao.fetch(Topic.class, topicId); bigContentService.fill(topic); _add(topic); } luceneIndex.writer.commit(); }
@Aop("redis") public CResult addReply(final String topicId, final TopicReply reply, final int userId) { if (userId < 1) return _fail("请先登录"); if (reply == null || reply.getContent() == null || reply.getContent().trim().isEmpty()) { return _fail("内容不能为空"); } final String cnt = reply.getContent().trim(); final Topic topic = dao.fetch(Topic.class, topicId); // TODO 改成只fetch出type属性 if (topic == null) { return _fail("主题不存在"); } if (topic.isLock()) { return _fail("该帖子已经锁定,不能回复"); } reply.setTopicId(topicId); reply.setUserId(userId); reply.setContent(Toolkit.filteContent(reply.getContent())); reply.setContentId(bigContentService.put(reply.getContent())); reply.setContent(null); dao.insert(reply); // 更新索引 topicSearchService.add(topic); // 更新topic的时间戳 Pipeline pipe = jedis().pipelined(); if (topic.isTop()) { pipe.zadd(RKEY_TOPIC_TOP, reply.getCreateTime().getTime(), topicId); } else { pipe.zadd(RKEY_TOPIC_UPDATE + topic.getType(), reply.getCreateTime().getTime(), topicId); pipe.zadd(RKEY_TOPIC_UPDATE_ALL, reply.getCreateTime().getTime(), topicId); } pipe.zrem(RKEY_TOPIC_NOREPLY, topicId); if (topic.getTags() != null) { for (String tag : topic.getTags()) { pipe.zadd( RKEY_TOPIC_TAG + tag.toLowerCase().trim(), reply.getCreateTime().getTime(), topicId); } } pipe.hset(RKEY_REPLY_LAST, topicId, reply.getId()); pipe.zincrby(RKEY_REPLY_COUNT, 1, topicId); pipe.zincrby(RKEY_USER_SCORE, 10, "" + userId); pipe.sync(); notifyUsers(topic, reply, cnt, userId); return _ok(reply.getId()); }
@Aop("redis") public void fillTopic(Topic topic, Map<Integer, UserProfile> authors) { if (topic.getUserId() == 0) topic.setUserId(1); topic.setAuthor(_cacheFetch(authors, topic.getUserId())); Double reply_count = jedis().zscore(RKEY_REPLY_COUNT, topic.getId()); topic.setReplyCount(reply_count == null ? 0 : reply_count.intValue()); if (topic.getReplyCount() > 0) { String replyId = jedis().hget(RKEY_REPLY_LAST, topic.getId()); TopicReply reply = dao.fetch(TopicReply.class, replyId); if (reply != null) { if (reply.getUserId() == 0) reply.setUserId(1); reply.setAuthor(_cacheFetch(authors, reply.getUserId())); topic.setLastComment(reply); } } Double visited = jedis().zscore(RKEY_TOPIC_VISIT, topic.getId()); topic.setVisitCount((visited == null) ? 0 : visited.intValue()); }
@Override public Item find(long id) { return dao.fetch(Item.class, id); }
/** * 找到一个tag和级联的信息 * * @param id * @return */ public Resource get(Integer id) { Resource resource = dao.fetch(Resource.class, id); resourceRelationFull(resource); return resource; }
@SuppressWarnings("serial") public void init(NutConfig nc) { NutShiro.DefaultLoginURL = "/admin/logout"; // 检查环境 if (!Charset.defaultCharset().name().equalsIgnoreCase(Encoding.UTF8)) { log.warn("This project must run in UTF-8, pls add -Dfile.encoding=UTF-8 to JAVA_OPTS"); } // 获取Ioc容器及Dao对象 Ioc ioc = nc.getIoc(); // 加载freemarker自定义标签 自定义宏路径 ioc.get(Configuration.class) .setAutoImports( new HashMap<String, String>(2) { { put("p", "/ftl/pony/index.ftl"); put("s", "/ftl/spring.ftl"); } }); ioc.get(FreeMarkerConfigurer.class, "mapTags"); Dao dao = ioc.get(Dao.class); // 为全部标注了@Table的bean建表 Daos.createTablesInPackage(dao, getClass().getPackage().getName() + ".bean", false); // 获取配置对象 PropertiesProxy conf = ioc.get(PropertiesProxy.class, "conf"); // 初始化SysLog,触发全局系统日志初始化 ioc.get(SysLogService.class); // 初始化默认根用户 User admin = dao.fetch(User.class, "admin"); if (admin == null) { UserService us = ioc.get(UserService.class); admin = us.add("admin", "123456"); } // 初始化游客用户 User guest = dao.fetch(User.class, "guest"); if (guest == null) { UserService us = ioc.get(UserService.class); guest = us.add("guest", "123456"); UserProfile profile = dao.fetch(UserProfile.class, guest.getId()); profile.setNickname("游客"); dao.update(profile, "nickname"); } // 获取NutQuartzCronJobFactory从而触发计划任务的初始化与启动 ioc.get(NutQuartzCronJobFactory.class); // 权限系统初始化 AuthorityService as = ioc.get(AuthorityService.class); as.initFormPackage("net.wendal.nutzbook"); as.checkBasicRoles(admin); // 检查一下Ehcache CacheManager 是否正常. CacheManager cacheManager = ioc.get(CacheManager.class); log.debug("Ehcache CacheManager = " + cacheManager); // CachedNutDaoExecutor.DEBUG = true; // 启用FastClass执行入口方法 Mvcs.disableFastClassInvoker = false; // 设置Markdown缓存 if (cacheManager.getCache("markdown") == null) cacheManager.addCache("markdown"); Markdowns.cache = cacheManager.getCache("markdown"); if (conf.getBoolean("cdn.enable", false) && !Strings.isBlank(conf.get("cdn.urlbase"))) { MarkdownFunction.cdnbase = conf.get("cdn.urlbase"); } }
@At("/id/?") @Ok("json") public Object storeid(int id) { return dao.fetch(Store.class, id); }