За вами следят! - Комментарии

  

За вами смотрят
  Обзор кода имеет открытую систему
  Машина, которая шпионит за вами каждый час каждый день
  Я знаю, потому что я его построил.   Я разработал машину для обнаружения предложений для публикации в обзоре кода, но он видит все   Ужасные комментарии, связанные с обычными пользователями
  Пользователи, как вы,   Комментарии, которые Stack Exchange считает неуместными   Они не будут действовать, поэтому я решил, что буду   Но мне нужны были партнеры   Регулярно с навыками вмешательства   Любимый модераторами, мы работаем в чате
  Вы можете легко найти нас   Но по теме или вне темы, если ваш комментарий вверх   Мы найдем вас   ( личный интерес, вступивший в силу , адаптированный к комментариям по интересам)

Некоторое время пользователи Stack Overflow размещали комментарии, направляющие людей на пост в Code Review. Несколько раз в Stack Overflow Meta было отмечено, что пользователи должны быть осторожно при этом . Чтобы обучить пользователей Stack Overflow, на которых есть записи, которые здесь, а что нет, я решил включить эту функцию в мой SE-chatbot называется Duga .

Бот работает в среде Spring MVC. Он использует API-интерфейс стека , чтобы проверять комментарии «Переполнение стека» раз в две минуты. Он просматривает полученные комментарии и публикует их в втором мониторе , где завсегдатаи могут проверять переполнение стека вопрос, чтобы определить, принадлежит ли это кодовому обзору или нет. Он также отправляет некоторую информацию в специальном чате, когда есть сообщение, которое меня интересует, - когда в последнее время было слишком много комментариев или когда таинственная квота ставок сбрасывается. (Я не ожидаю, что это будет 100 комментариев очень часто. Пока это не произошло в течение двух минут)

Если вы хотите увидеть пример результата API, вы можете использовать этот ссылка

Репозиторий Github для всего бота можно найти здесь

ScheduledTasks.java (соответствующие части)

@Autowired
private ChatBot chatBot;

@Autowired
private StackExchangeAPIBean stackAPI;

private Instant nextFetch = Instant.now();
private long lastComment;
private long fromDate;
private int remainingQuota;

private final WebhookParameters params = WebhookParameters.toRoom("8595");
private final WebhookParameters debug = WebhookParameters.toRoom("20298");

@Scheduled(cron = "0 */2 * * * *") // second minute hour day day day
public void scanComments() {
    if (!Instant.now().isAfter(nextFetch)) {
        return;
    }

    try {
        StackComments comments = stackAPI.fetchComments("stackoverflow", fromDate);
        int currentQuota = comments.getQuotaRemaining();
        if (currentQuota > remainingQuota && fromDate != 0) {
            chatBot.postMessage(debug, Instant.now() + " Quota has been reset. Was " + remainingQuota + " is now " + currentQuota);
        }
        remainingQuota = currentQuota;
        List<StackExchangeComment> items = comments.getItems();
        if (items != null) {
            if (items.size() >= 100) {
                chatBot.postMessage(debug, Instant.now() + " Warning: Retrieved 100 comments. Might have missed some. This is unlikely to happen");
            }

            long previousLastComment = lastComment;
            for (StackExchangeComment comment : items) {
                if (comment.getCommentId() <= previousLastComment) {
                    continue;
                }
                lastComment = Math.max(comment.getCommentId(), lastComment);
                fromDate = Math.max(comment.getCreationDate(), fromDate);
                if (isInterestingComment(comment)) {
                    chatBot.postMessage(params, comment.getLink());
                }
            }
        }
        if (comments.getBackoff() != 0) {
            nextFetch = Instant.now().plusSeconds(comments.getBackoff() + 10);
            chatBot.postMessage(debug, Instant.now() + " Next fetch: " + nextFetch + " because of backoff " + comments.getBackoff());
        }
    } catch (Exception e) {
        logger.error("Error retrieving comments", e);
        chatBot.postMessage(debug, Instant.now() + " Exception in comment task " + e);
        return;
    }
}

private boolean isInterestingComment(StackExchangeComment comment) {
    String commentText = comment.getBodyMarkdown().toLowerCase();
    return commentText.contains("code review") || commentText.contains("codereview");
}

WebhookParameters.java

public class WebhookParameters {

    private String roomId;
    private Boolean post;

    public String getRoomId() {
        return roomId;
    }

    public void setRoomId(String roomId) {
        this.roomId = roomId;
    }

    public void useDefaultRoom(String defaultRoomId) {
        if (roomId == null) {
            roomId = defaultRoomId;
        }
    }

    public boolean getPost() {
        return post == null ? true : post;
    }

    public void setPost(Boolean post) {
        this.post = post;
    }

    public static WebhookParameters toRoom(String roomId) {
        WebhookParameters params = new WebhookParameters();
        params.setPost(true);
        params.setRoomId(roomId);
        return params;
    }

}

StackExchangeAPIBean.java

public class StackExchangeAPIBean {

    private final ObjectMapper mapper = new ObjectMapper();

    @Autowired
    private BotConfiguration config;

    public StackExchangeAPIBean() {
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    public StackComments fetchComments(String site, long fromDate) throws JsonParseException, JsonMappingException, IOException {
        final String filter = "!1zSk*x-OuqVk2k.(bS0NB";
        final String apiKey = config.getStackAPIKey();
        URL url = new URL("https://api.stackexchange.com/2.2/comments?page=1&pagesize=100&fromdate=" + fromDate +
                "&order=desc&sort=creation&site=" + site + "&filter=" + filter + "&key=" + apiKey);
        URLConnection connection = url.openConnection();
        connection.setRequestProperty("Accept-Encoding", "identity");

        return mapper.readValue(new GZIPInputStream(connection.getInputStream()), StackComments.class);
    }

}

StackComments.java

public class StackComments {

    @JsonProperty
    private List<StackExchangeComment> items;

    @JsonProperty("has_more")
    private boolean hasMore;

    @JsonProperty("quota_max")
    private int quotaMax;

    @JsonProperty("quota_remaining")
    private int quotaRemaining;

    @JsonProperty
    private int backoff;

    @JsonProperty("error_id")
    private int errorId;

    @JsonProperty("error_message")
    private String errorMessage;

    @JsonProperty("error_name")
    private String errorName;

    public int getBackoff() {
        return backoff;
    }

    public int getErrorId() {
        return errorId;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

    public String getErrorName() {
        return errorName;
    }

    public List<StackExchangeComment> getItems() {
        return items;
    }

    public int getQuotaMax() {
        return quotaMax;
    }

    public int getQuotaRemaining() {
        return quotaRemaining;
    }

}

StackExchangeComment.java

public class StackExchangeComment {

    @JsonProperty("post_id")
    private long postId;

    @JsonProperty("comment_id")
    private long commentId;

    @JsonProperty("creation_date")
    private long creationDate;

    @JsonProperty
    private String body;

    @JsonProperty
    private String link;

    @JsonProperty("body_markdown")
    private String bodyMarkdown;

    public String getBody() {
        return body;
    }

    public String getBodyMarkdown() {
        return bodyMarkdown;
    }

    public long getCommentId() {
        return commentId;
    }

    public long getPostId() {
        return postId;
    }

    public String getLink() {
        return link;
    }

    public long getCreationDate() {
        return creationDate;
    }

}

Мне известно, что WebhookParameters не является неизменным, это связано прежде всего с тем, что его можно использовать в качестве параметров запроса URL в Spring MVC.

Вопросы

  • Есть ли способ упростить код?
  • Я использую API-интерфейс Stack Exchange в хорошем смысле?
  • Любые другие комментарии?
54 голоса | спросил Simon Forsberg 3 FebruaryEurope/MoscowbTue, 03 Feb 2015 03:01:11 +0300000000amTue, 03 Feb 2015 03:01:11 +030015 2015, 03:01:11

2 ответа


27

У меня есть одна в категории «любые другие комментарии»:)


Локализация?

Я знаю, это не проблема. Или это? Кажется, что локализация осталась позади! По иронии судьбы, именно по этой причине локализация приложения чаще всего - боль в шее.

Но тогда, насколько сложнее, действительно, написать это:

if (items.size() >= 100) {
    chatBot.postMessage(debug, Instant.now() + " Warning: Retrieved 100 comments. Might have missed some. This is unlikely to happen");
}

Вроде:

if (items.size() >= 100) {
    chatBot.postMessage(debug, Instant.now() + Resources.Warn100CommentsReceived);
}

Я предполагаю имеет что-то , например resources здесь, извинения, если я просто засунул ногу в рот. Он выглядит более чистым, хотя:)


«100» - это магическое число

Тем не менее, items.size() >= 100 не является «100 полученными комментариями» - сообщение не отражает то, что делает код, а это означает, что это когда-либо так мало возможно , что сообщение cake является ложью. И если вы когда-нибудь испортите этот предел, вы, вероятно, захотите узнать насколько.

Как получить извлечение переменной из items.size() и объединить ее в сообщение вместо жестко закодированного 100?

На основе последние 26 недель активности на стеке Переполнение , цифры будут следующими:

  • 4 320 919 комментариев.
  • Между комментариями 116 900 и 188 280 - 166 190 в среднем за неделю.
  • В среднем за 52 недели 177,757 комментариев в неделю: месяцы впереди будут, вероятно, более занятыми, чем те, которые позади нас.
  • Это 16,5 комментариев в минуту, 32.97 за две минуты.

Я согласен с тем, что 100 - разумное число для использования. Но ... «100» - магическое число ! В то время как вы получили 30 комментариев за две минуты, по крайней мере 4-5 новых пользователей присоединились к Stack Overflow (~ 23K новых пользователей в неделю) - при такой скорости 100 возможно, в конечном итоге, должно быть заменяется на большее число. Значение абсолютно произвольное (почему не 255?) И явно принадлежит как private static final - это то, где я ожидал бы его найти, если не в настройках /файле приложения.

ответил Mathieu Guindon 3 FebruaryEurope/MoscowbTue, 03 Feb 2015 07:49:57 +0300000000amTue, 03 Feb 2015 07:49:57 +030015 2015, 07:49:57
19

Как Матовая кружка уже , у вас есть некоторые магические числа в вашем коде.

private final WebhookParameters params = WebhookParameters.toRoom("8595");
private final WebhookParameters debug = WebhookParameters.toRoom("20298");  

избавиться от них.


Вы не должны жестко закодировать api url. Вместо этого поместите его в файл конфигурации. Если api изменяется, значит, и URL. Если изменения не нарушают ваше приложение, возможно, URL.

Может быть, метод Url composeUrl() будет хорошей идеей.


Жесткое кодирование значений, делающих комментарий интересным, также не должно выполняться.


ИМХО, вы немного разбираетесь в методе scanComments(). Вы извлекаете комментарии из StackExchangeAPIBean, обрабатываете оставшуюся квоту, обрабатываете комментарии и вычисляете следующую выборку по значению отсрочки. Это должно /могло быть извлечено для разделения методов.


Если исключение выбрано chatBot.postMessage, это также произойдет внутри части catch. Вы должны лучше заключить метод postMessage() в try..catch и генерировать собственное исключение, которое затем не должно обрабатываться путем вызова postMessage() снова.


Метод useDefaultRoom() немного странный IMHO. Я бы переименовал его в setRoomIdIfNull(), но я не вижу в этом никакого смысла (может быть, какой-то недостающий контекст?).


ответил Heslacher 3 FebruaryEurope/MoscowbTue, 03 Feb 2015 10:34:00 +0300000000amTue, 03 Feb 2015 10:34:00 +030015 2015, 10:34:00

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132