Advertisement
Guest User

Untitled

a guest
Sep 18th, 2016
146
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.75 KB | None | 0 0
  1. from urllib.request import urlopen
  2. from urllib.error import URLError
  3. from urllib.parse import urlparse
  4. from datetime import datetime
  5. from slacker import Slacker
  6. from jsonifier import TableJSONifier
  7. from onesignal import OneSignal
  8. import logging, psycopg2, os, re
  9.  
  10. class TimeTableBot:
  11. months = {'ЯНВАРЯ': 1,
  12. 'ФЕВРАЛЯ': 2,
  13. 'МАРТА': 3,
  14. 'АПРЕЛЯ': 4,
  15. 'МАЯ': 5,
  16. 'ИЮНЯ': 6,
  17. 'ИЮЛЯ': 7,
  18. 'АВГУСТА': 8,
  19. 'СЕНТЯБРЯ': 9,
  20. 'ОКТЯБРЯ': 10,
  21. 'НОЯБРЯ': 11,
  22. 'ДЕКАБРЯ': 12}
  23.  
  24. curr_date = datetime.now()
  25.  
  26. # Set up logging
  27. log_level = logging.DEBUG
  28.  
  29. log = logging.Logger('bot')
  30. log.setLevel(log_level)
  31.  
  32. log_handler = logging.StreamHandler()
  33. log_handler.setLevel(log_level)
  34.  
  35. log_fmt = logging.Formatter('[{asctime}] [{levelname}]\n{message}\n',
  36. datefmt = '%d-%m %H:%M:%S', style = '{')
  37. log_handler.setFormatter(log_fmt)
  38.  
  39. log.addHandler(log_handler)
  40.  
  41. def connect(self):
  42. """Connects to the database"""
  43. self.url = urlparse(os.environ["DATABASE_URL"])
  44. self.log.info('connecting to the database')
  45. self.db = psycopg2.connect(database=self.url.path[1:],
  46. user=self.url.username,
  47. password=self.url.password,
  48. host=self.url.hostname,
  49. port=self.url.port)
  50.  
  51. self.c = self.db.cursor()
  52. self.log.info('connection established')
  53.  
  54. def already_sent(self):
  55. """Checks if the changes were sent already"""
  56. self.c.execute('''SELECT tm FROM date''')
  57. tm = float(self.c.fetchone()[0])
  58. self.changes_sent = datetime.fromtimestamp(tm)
  59. if self.changes_sent > self.curr_date:
  60. return True
  61. return False
  62.  
  63. def get_table_page(self, addr, enc):
  64. """Gets the changes page's content"""
  65. self.log.info('fetching table page')
  66. page = urlopen(addr).read().decode(enc)
  67. self.log.info('fetch successful')
  68. print(page)
  69. return page
  70.  
  71. def parse_header(self, page):
  72. """Dissects the heading in the changes page"""
  73. header = re.search('ИЗМЕНЕНИЯ В РАСПИСАНИИ НА ([А-Я]+), ([0-9]+) ([А-Я]+)', page)
  74. try:
  75. self.wkday, self.day, self.month = header.group(1, 2, 3)
  76. self.wkday = self.wkday.lower()
  77. return True
  78. except AttributeError:
  79. return False
  80.  
  81. def parse_changes(self, page):
  82. """Returns a list of changes for both classes
  83. (if they're present)"""
  84. changes_e = []
  85. changes = re.findall(r'<h2>([0-9]{1,2}[А-С])<\/h2>\n<p>((\n|.)+?)(?=(<\/body>|<h2>))', page)
  86. print(changes)
  87. for i in changes:
  88. print(i)
  89. cls, chg = i[:2]
  90. chg = chg.replace('<p>', '')
  91. chg = chg.replace('</p>', '')
  92. chg = chg.replace('&nbsp;&mdash;', ' –')
  93. if cls in ('10Е', '11Е'):
  94. changes_e.append((cls, chg))
  95. self.log.info('found updates for ' + cls)
  96. self.log.info('sending push for ' + cls)
  97. OneSignal.send(cls, chg.replace('\n', ', '), self.wkday)
  98.  
  99. return changes_e
  100.  
  101. def set_timestamp(self, change_date):
  102. """Sets the new timestamp"""
  103. tm = int(change_date.timestamp())
  104. self.log.info('setting a new timestamp in the database')
  105. self.c.execute('''UPDATE date SET tm = %s''', (tm,))
  106. self.db.commit()
  107.  
  108. def send_slack(self, attachments):
  109. """Sends a message to Slack"""
  110. # Create a Slack bot instance
  111. slack = Slacker(os.environ['SLACK_API_TOKEN'])
  112.  
  113. # Send a message to #general channel
  114. self.log.info('sending a message to Slack')
  115. slack.chat.post_message('#general',
  116. text = ' ',
  117. username = 'timetable',
  118. icon_emoji = ':spiral_calendar_pad:',
  119. attachments = attachments)
  120.  
  121. def run(self):
  122. self.log.info('starting up')
  123.  
  124. self.connect()
  125.  
  126. if self.already_sent():
  127. self.log.info('already up-to-date, quitting')
  128. self.log.debug('latest update sent for ' +
  129. self.changes_sent.strftime('%d-%m-%Y'))
  130. return
  131.  
  132. try:
  133. self.page = self.get_table_page(os.environ['TIMETABLE_URL'],
  134. os.environ['TIMETABLE_ENC'])
  135. except URLError:
  136. self.log.error('failed to fetch page, quitting')
  137. return -1
  138.  
  139. if not self.parse_header(self.page):
  140. self.log.error('table invalid, quitting')
  141. return -1
  142.  
  143. self.change_date = datetime(self.curr_date.year,
  144. self.months[self.month],
  145. int(self.day))
  146.  
  147. if self.change_date < self.curr_date:
  148. self.log.info('table outdated, quitting')
  149. return
  150.  
  151. self.changes_e = self.parse_changes(self.page)
  152.  
  153. if self.changes_e:
  154. self.log.info('generating JSON message')
  155. atch = TableJSONifier.make_attachment(self.wkday,
  156. self.changes_e)
  157. self.send_slack(atch)
  158.  
  159. self.set_timestamp(self.change_date)
  160.  
  161. self.db.close()
  162. self.log.info('success, quitting')
  163.  
  164. TimeTableBot().run()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement