<commit_before>package controllers;

import info.schleichardt.play2.mailplugin.Mailer;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import play.Logger;
import play.db.ebean.Model;

import models.resource.Resource;

import models.*;
import models.enumeration.Direction;
import models.enumeration.Operation;
import models.enumeration.ResourceType;

import play.data.Form;
import play.libs.Akka;
import play.mvc.*;
import utils.AccessControl;

import utils.Callback;
import utils.Config;
import utils.Constants;

import java.io.IOException;
import java.util.Set;
import java.util.concurrent.Callable;

/**
 * {@link BoardApp}과 {@link IssueApp}에서 공통으로 사용하는 기능을 담고 있는 컨트롤러 클래스
 */
public class AbstractPostingApp extends Controller {
    public static final int ITEMS_PER_PAGE = 15;

    /**
     * 검색 조건
     */
    public static class SearchCondition {
        public String orderBy;
        public String orderDir;
        public String filter;
        public int pageNum;

        /**
         * 기본 검색 조건으로 id 역순이며 1페이지를 보여준다.
         */
        public SearchCondition() {
            this.orderDir = Direction.DESC.direction();
            this.orderBy = "id";
            this.filter = "";
            this.pageNum = 1;
        }
    }

    /**
     * 새 댓글 저장 핸들러
     *
     * {@code commentForm}에서 입력값을 꺼내 현재 사용자를 작성자로 설정하고 댓글을 저장한다.
     * 현재 사용자 임시 저장소에 있는 첨부파일을 댓글의 첨부파일로 옮긴다.
     *
     * @param comment
     * @param commentForm
     * @param toView
     * @param containerUpdater
     * @return
     * @throws IOException
     */
    public static Result newComment(final Comment comment, Form<? extends Comment> commentForm, final Call toView, Callback containerUpdater) throws IOException {
        if (commentForm.hasErrors()) {
            flash(Constants.WARNING, "board.comment.empty");
            return redirect(toView);
        }

        comment.setAuthor(UserApp.currentUser());
        containerUpdater.run(); // this updates comment.issue or comment.posting;
        comment.save();

        // Attach all of the files in the current user's temporary storage.
        Attachment.moveAll(UserApp.currentUser().asResource(), comment.asResource());

        try {
            sendNotification(comment, toView.absoluteURL(request()));
        } catch (Exception e) {
            Logger.warn("Failed to send a notification: " + ExceptionUtils.getStackTrace(e));
        }

        return redirect(toView);
    }

    /**
     * 어떤 게시물에 댓글이 달렸을 때, 그 게시물을 지켜보는 사용자들에게 알림 메일을 발송한다.
     *
     * @param comment
     * @param urlToView
     * @see <a href="https://github.com/nforge/hive/blob/master/docs/technical/watch.md>watch.md</a>
     */
    private static void sendNotification(Comment comment, String urlToView) {
        User sender = UserApp.currentUser();
        AbstractPosting parent = comment.getParent();

        Set<User> receivers = parent.getWatchers();
        receivers.remove(User.find.byId(comment.authorId));

        String subject = String.format(
                "Re: [%s] %s (#%d)",
                parent.project.name, parent.title, parent.getNumber());
        String urlToComment = urlToView + "#comment-" + comment.id;
        String htmlMessage = String.format(
                "<pre>%s</pre><hr><a href=\"%s\">%s</a>",
                comment.contents, urlToComment, "View it on HIVE");
        String plainMessage = String.format(
                "%s\n\n--\nView it on %s",
                comment.contents, urlToComment);

        final HtmlEmail email = new HtmlEmail();

        try {
            email.setFrom(Config.getEmailFromSmtp());
            for (User receiver : receivers) {
                email.addTo(receiver.email, receiver.name);
            }
            email.setSubject(subject);
            email.setHtmlMsg(htmlMessage);
            email.setTextMsg(plainMessage);<commit_msg>notification: Do not send mail to anonymous.<commit_after>package controllers;

import info.schleichardt.play2.mailplugin.Mailer;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import play.Logger;
import play.db.ebean.Model;

import models.resource.Resource;

import models.*;
import models.enumeration.Direction;
import models.enumeration.Operation;
import models.enumeration.ResourceType;

import play.data.Form;
import play.libs.Akka;
import play.mvc.*;
import utils.AccessControl;

import utils.Callback;
import utils.Config;
import utils.Constants;

import java.io.IOException;
import java.util.Set;
import java.util.concurrent.Callable;

/**
 * {@link BoardApp}과 {@link IssueApp}에서 공통으로 사용하는 기능을 담고 있는 컨트롤러 클래스
 */
public class AbstractPostingApp extends Controller {
    public static final int ITEMS_PER_PAGE = 15;

    /**
     * 검색 조건
     */
    public static class SearchCondition {
        public String orderBy;
        public String orderDir;
        public String filter;
        public int pageNum;

        /**
         * 기본 검색 조건으로 id 역순이며 1페이지를 보여준다.
         */
        public SearchCondition() {
            this.orderDir = Direction.DESC.direction();
            this.orderBy = "id";
            this.filter = "";
            this.pageNum = 1;
        }
    }

    /**
     * 새 댓글 저장 핸들러
     *
     * {@code commentForm}에서 입력값을 꺼내 현재 사용자를 작성자로 설정하고 댓글을 저장한다.
     * 현재 사용자 임시 저장소에 있는 첨부파일을 댓글의 첨부파일로 옮긴다.
     *
     * @param comment
     * @param commentForm
     * @param toView
     * @param containerUpdater
     * @return
     * @throws IOException
     */
    public static Result newComment(final Comment comment, Form<? extends Comment> commentForm, final Call toView, Callback containerUpdater) throws IOException {
        if (commentForm.hasErrors()) {
            flash(Constants.WARNING, "board.comment.empty");
            return redirect(toView);
        }

        comment.setAuthor(UserApp.currentUser());
        containerUpdater.run(); // this updates comment.issue or comment.posting;
        comment.save();

        // Attach all of the files in the current user's temporary storage.
        Attachment.moveAll(UserApp.currentUser().asResource(), comment.asResource());

        try {
            sendNotification(comment, toView.absoluteURL(request()));
        } catch (Exception e) {
            Logger.warn("Failed to send a notification: " + ExceptionUtils.getStackTrace(e));
        }

        return redirect(toView);
    }

    /**
     * 어떤 게시물에 댓글이 달렸을 때, 그 게시물을 지켜보는 사용자들에게 알림 메일을 발송한다.
     *
     * @param comment
     * @param urlToView
     * @see <a href="https://github.com/nforge/hive/blob/master/docs/technical/watch.md>watch.md</a>
     */
    private static void sendNotification(Comment comment, String urlToView) {
        User sender = UserApp.currentUser();
        AbstractPosting parent = comment.getParent();

        Set<User> receivers = parent.getWatchers();
        receivers.remove(User.find.byId(comment.authorId));
        receivers.remove(User.anonymous);

        String subject = String.format(
                "Re: [%s] %s (#%d)",
                parent.project.name, parent.title, parent.getNumber());
        String urlToComment = urlToView + "#comment-" + comment.id;
        String htmlMessage = String.format(
                "<pre>%s</pre><hr><a href=\"%s\">%s</a>",
                comment.contents, urlToComment, "View it on HIVE");
        String plainMessage = String.format(
                "%s\n\n--\nView it on %s",
                comment.contents, urlToComment);

        final HtmlEmail email = new HtmlEmail();

        try {
            email.setFrom(Config.getEmailFromSmtp());
            for (User receiver : receivers) {
                email.addTo(receiver.email, receiver.name);
            }
            email.setSubject(subject);
            email.setHtmlMsg(htmlMessage);
            email.setTextMsg(plainMessage);
{'fraction_non_alphanumeric': 0.11116681288382002, 'fraction_numerical': 0.0012532898859506205, 'mean_word_length': 2.4087996582656985, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1773173', 'n_tokens_mistral': 2582, 'n_tokens_neox': 2712, 'n_words': 564}