<commit_before># Description:
#   Your dog friend can keep you in line
#
# Commands:
#   ibizan stop ibizan - Disable hounding until the following morning
#   ibizan disable ibizan - See `stop ibizan`
# Notes:
#   Ibizan will DM an employee as soon as they’ve posted in Slack after
#   more than [houndFrequency] hours of inactivity.
#   If the user is logged out, the DM should say:
#     Check in if you’re on the clock~
#   If the user is logged in, the DM should say:
#     Don’t forget to check out~
# Author:
#   aaronsky

moment = require 'moment'
schedule = require 'node-schedule'

{ STRINGS, TIMEZONE } = require '../helpers/constants'
Organization = require('../models/organization').get()
strings = STRINGS.hound

module.exports = (robot) ->
  Logger = require('../helpers/logger')(robot)

  # Generates a random [in/out] hound message
  houndMessage = (mode) ->
    message = ""
    if mode is 'in'
      message += strings.punchin[Math.floor(Math.random() * strings.punchin.length)]
    else if mode is 'out'
      message += strings.punchout[Math.floor(Math.random() * strings.punchout.length)]
    else if mode is 'tempout'
      message += strings.tempout
    if (Math.floor(Math.random() * 6) + 1) == 1
      message += strings.annoying
    return message

  hound = (slackuser, channel, forceHound=false, passive=false) ->
    if robot.name is slackuser.name
      Logger.debug "Caught myself, don't hound the hound."
      return
    else if not Organization.ready()
      Logger.debug "Don't hound, Organization isn't ready yet"
      return

    user = Organization.getUserBySlackName slackuser.name
    if not user
      Logger.debug "#{slackuser.name} couldn't be found while attempting to hound"
      return

    if user.settings.shouldHound and user.settings.houndFrequency > 0
      if not channel.private
        channel.private = !!channel.is_im or !!channel.is_group
      if channel.private or
         channel.name in Organization.exemptChannels
        Logger.debug "##{channel.name} is not an appropriate hounding channel"
        return

      now = moment.tz user.timetable.timezone.name
      last = user.settings?.lastMessage || { time: now, channel: channel.name }
      user.settings?.fromSettings {
        lastMessage: {
          time: now,
          channel: channel.name
        }
      }

      [start, end] = user.activeHours()
      lastPunch = user.lastPunch ['in', 'out', 'vacation', 'sick', 'unpaid']
      lastPing = user.settings?.lastPing || now
      timeSinceStart = +Math.abs(now.diff(start, 'hours', true)).toFixed(2) || 0
      timeSinceEnd = +Math.abs(now.diff(end, 'hours', true)).toFixed(2) || 0
      timeSinceLastPunch = now.diff(lastPunch?.times.slice(-1)[0], 'hours', true) || 0
      timeSinceLastMessage = user
                             .settings?.lastMessage
                             .time.diff(last.time, 'hours', true) || 0
      timeSinceLastPing = +Math.abs(now.diff(lastPing, 'hours', true)) || 0

      Logger.debug "now: #{now.format('h:mm A, z')},
                    isInactive: #{user.isInactive()},
                    start: #{start.format('h:mm A')},
                    end: #{end.format('h:mm A')},
                    timeSinceLastPunch: #{timeSinceLastPunch},
                    timeSinceLastMessage: #{timeSinceLastMessage},
                    timeSinceStart: #{timeSinceStart},
                    timeSinceEnd: #{timeSinceEnd},
                    timeSinceLastPing: #{timeSinceLastPing},
                    houndFrequency: #{user.settings.houndFrequency}"

      if (timeSinceLastPing == 0 or timeSinceLastPing >= user.settings.houndFrequency) and
         timeSinceLastPunch > 0.25
        if user.salary
          if not lastPunch and not user.isInactive() and not passive
            Logger.debug "Considering hounding #{user.slack} because of missing lastPunch during active period"
            if now.isAfter(start) and timeSinceStart >= 0.5
              user.hound houndMessage('in'), Logger
            else if now.isAfter(end) and timeSinceEnd >= 0.5
              user.hound houndMessage('out'), Logger
          else if lastPunch.mode is 'in' and user.isInactive()
            Logger.debug "Considering hounding #{user.slack} because lastPunch is in and it's outside of their active period"
            if timeSinceEnd >= 0.5
              user.hound houndMessage('out'), Logger
          else if lastPunch.mode is 'out' and not passive
            Logger.debug "Considering hounding #{user.slack} because lastPunch is out during active period"
            if not user.isInactive() and timeSinceStart >= 0.5
              user.hound houndMessage('in'), Logger
          else if lastPunch.mode is 'vacation' or
                  lastPunch.mode is 'sick' or
                  lastPunch.mode is 'unpaid'
            Logger.debug "Considering hounding #{user.slack} because lastPunch is special"
            if lastPunch.times.length > 0 and not now.isBetween(lastPunch.times[0], lastPunch.times[1]) and not passive
              user.hound houndMessage('in'), Logger
            else if lastPunch.times.block? and not passive
              endOfBlock = moment(lastPunch.date).add(lastPunch.times.block, 'hours')
              if not now.isBetween(lastPunch.date, endOfBlock)
                user.hound houndMessage('in'), Logger
          else
            Logger.debug "Considering hounding #{user.slack} because it's during their active period with no in punch"
            if now.isAfter(start) and timeSinceStart >= 0.5 and not passive
              user.hound houndMessage('in'), Logger
            else if now.isAfter(end) and timeSinceEnd >= 0.5 and not passive
              user.hound houndMessage('out'), Logger
        else # Part-timer-only hounding
          if lastPunch and lastPunch.mode is 'in' and timeSinceLastPunch > 4
            user.hound houndMessage('tempout'), Logger
      else if timeSinceLastPunch <= 0.25 and user.salary
        Logger.debug "#{user.slack} is safe from hounding as they punched
                      #{timeSinceLastPunch.toFixed(2)} hours ago"
      else
        Logger.debug "#{user.slack} is safe from hounding for another
                      #{user.settings.houndFrequency - timeSinceLastPing.toFixed(2)} hours"
<commit_msg>Removed else from hound checking, was catching block punches as false positives<commit_after># Description:
#   Your dog friend can keep you in line
#
# Commands:
#   ibizan stop ibizan - Disable hounding until the following morning
#   ibizan disable ibizan - See `stop ibizan`
# Notes:
#   Ibizan will DM an employee as soon as they’ve posted in Slack after
#   more than [houndFrequency] hours of inactivity.
#   If the user is logged out, the DM should say:
#     Check in if you’re on the clock~
#   If the user is logged in, the DM should say:
#     Don’t forget to check out~
# Author:
#   aaronsky

moment = require 'moment'
schedule = require 'node-schedule'

{ STRINGS, TIMEZONE } = require '../helpers/constants'
Organization = require('../models/organization').get()
strings = STRINGS.hound

module.exports = (robot) ->
  Logger = require('../helpers/logger')(robot)

  # Generates a random [in/out] hound message
  houndMessage = (mode) ->
    message = ""
    if mode is 'in'
      message += strings.punchin[Math.floor(Math.random() * strings.punchin.length)]
    else if mode is 'out'
      message += strings.punchout[Math.floor(Math.random() * strings.punchout.length)]
    else if mode is 'tempout'
      message += strings.tempout
    if (Math.floor(Math.random() * 6) + 1) == 1
      message += strings.annoying
    return message

  hound = (slackuser, channel, forceHound=false, passive=false) ->
    if robot.name is slackuser.name
      Logger.debug "Caught myself, don't hound the hound."
      return
    else if not Organization.ready()
      Logger.debug "Don't hound, Organization isn't ready yet"
      return

    user = Organization.getUserBySlackName slackuser.name
    if not user
      Logger.debug "#{slackuser.name} couldn't be found while attempting to hound"
      return

    if user.settings.shouldHound and user.settings.houndFrequency > 0
      if not channel.private
        channel.private = !!channel.is_im or !!channel.is_group
      if channel.private or
         channel.name in Organization.exemptChannels
        Logger.debug "##{channel.name} is not an appropriate hounding channel"
        return

      now = moment.tz user.timetable.timezone.name
      last = user.settings?.lastMessage || { time: now, channel: channel.name }
      user.settings?.fromSettings {
        lastMessage: {
          time: now,
          channel: channel.name
        }
      }

      [start, end] = user.activeHours()
      lastPunch = user.lastPunch ['in', 'out', 'vacation', 'sick', 'unpaid']
      lastPing = user.settings?.lastPing || now
      timeSinceStart = +Math.abs(now.diff(start, 'hours', true)).toFixed(2) || 0
      timeSinceEnd = +Math.abs(now.diff(end, 'hours', true)).toFixed(2) || 0
      timeSinceLastPunch = now.diff(lastPunch?.times.slice(-1)[0], 'hours', true) || 0
      timeSinceLastMessage = user
                             .settings?.lastMessage
                             .time.diff(last.time, 'hours', true) || 0
      timeSinceLastPing = +Math.abs(now.diff(lastPing, 'hours', true)) || 0

      Logger.debug "now: #{now.format('h:mm A, z')},
                    isInactive: #{user.isInactive()},
                    start: #{start.format('h:mm A')},
                    end: #{end.format('h:mm A')},
                    timeSinceLastPunch: #{timeSinceLastPunch},
                    timeSinceLastMessage: #{timeSinceLastMessage},
                    timeSinceStart: #{timeSinceStart},
                    timeSinceEnd: #{timeSinceEnd},
                    timeSinceLastPing: #{timeSinceLastPing},
                    houndFrequency: #{user.settings.houndFrequency}"

      if (timeSinceLastPing == 0 or timeSinceLastPing >= user.settings.houndFrequency) and
         timeSinceLastPunch > 0.25
        if user.salary
          if not lastPunch and not user.isInactive() and not passive
            Logger.debug "Considering hounding #{user.slack} because of missing lastPunch during active period"
            if now.isAfter(start) and timeSinceStart >= 0.5
              user.hound houndMessage('in'), Logger
            else if now.isAfter(end) and timeSinceEnd >= 0.5
              user.hound houndMessage('out'), Logger
          else if lastPunch.mode is 'in' and user.isInactive()
            Logger.debug "Considering hounding #{user.slack} because lastPunch is in and it's outside of their active period"
            if timeSinceEnd >= 0.5
              user.hound houndMessage('out'), Logger
          else if lastPunch.mode is 'out' and not passive
            Logger.debug "Considering hounding #{user.slack} because lastPunch is out during active period"
            if not user.isInactive() and timeSinceStart >= 0.5
              user.hound houndMessage('in'), Logger
          else if lastPunch.mode is 'vacation' or
                  lastPunch.mode is 'sick' or
                  lastPunch.mode is 'unpaid'
            Logger.debug "Considering hounding #{user.slack} because lastPunch is special"
            if lastPunch.times.length > 0 and not now.isBetween(lastPunch.times[0], lastPunch.times[1]) and not passive
              user.hound houndMessage('in'), Logger
            else if lastPunch.times.block? and not passive
              endOfBlock = moment(lastPunch.date).add(lastPunch.times.block, 'hours')
              if not now.isBetween(lastPunch.date, endOfBlock)
                user.hound houndMessage('in'), Logger
        else # Part-timer-only hounding
          if lastPunch and lastPunch.mode is 'in' and timeSinceLastPunch > 4
            user.hound houndMessage('tempout'), Logger
      else if timeSinceLastPunch <= 0.25 and user.salary
        Logger.debug "#{user.slack} is safe from hounding as they punched
                      #{timeSinceLastPunch.toFixed(2)} hours ago"
      else
        Logger.debug "#{user.slack} is safe from hounding for another
                      #{user.settings.houndFrequency - timeSinceLastPing.toFixed(2)} hours"

{'fraction_non_alphanumeric': 0.10512988073844143, 'fraction_numerical': 0.005881391929423297, 'mean_word_length': 2.4506764374295376, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 29, 'https://': 0, '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': '889471', 'n_tokens_mistral': 3662, 'n_tokens_neox': 3491, 'n_words': 1027}