def convert_date(raw_date: str) -> tuple: def _get_datetime_range(date: str) -> tuple: """ Makes one day period by received date. Parameters ---------- date: Date for report generating. Returns ------- Datetime range. """ date = datetime.strptime(date, "%Y-%m-%d") from_date = date.astimezone(utc) from_date = from_date.strftime("%Y-%m-%dT%H:%M:%S.%f%z") to_date = (date.replace( hour=23, minute=59, second=59).astimezone(utc).strftime("%Y-%m-%dT%H:%M:%S.%f%z")) return from_date, to_date parser = Calendar() date, status = parser.parse(raw_date) date = datetime(*date[:3]).strftime("%Y-%m-%d") return _get_datetime_range(date)
class Reminders(commands.Cog): """Set reminders.""" def __init__(self, bot: Bot): self.bot = bot self.cal = Calendar() self.remind_loop.start() @commands.command(name="remind", aliases=["remindme"]) async def remind(self, ctx: Context, t: str, *, message: str): """Set a reminder.""" parsed, success = self.cal.parse(t) if not success: return await ctx.reply("Please use a valid time string, such as 3d6h.") time = mktime(parsed) dt = datetime.fromtimestamp(time) td = dt - datetime.utcnow() total_diff = td.total_seconds() if total_diff < 5: return await ctx.reply("I can't create reminders less than 5 seconds in the future!") id = await self.bot.db.create_reminder(ctx.author.id, ctx.guild.id, ctx.channel.id, ctx.message.id, dt, message) await ctx.reply(f"Reminder created with ID {id} set to remind you at <t:{int(dt.timestamp())}:F>.") @tasks.loop(seconds=10) async def remind_loop(self): await self.bot.wait_until_ready() rs = await self.bot.db.get_expired_reminders() for reminder in rs: if reminder["expires"] > datetime.now(): continue logger.info(f"Actioning reminder ID {reminder['id']} from {reminder['userid']}") await self.bot.db.mark_reminder_completed(reminder["id"]) channel = self.bot.get_channel(reminder["cid"]) if not channel: continue jump = f"https://discord.com/channels/{reminder['gid']}/{reminder['cid']}/{reminder['mid']}" await channel.send( f"<@{reminder['userid']}> reminder:\n{reminder['content']}\n\nOriginal message: {jump}", allowed_mentions=AllowedMentions(users=True), )
def parse(self, response): # follow links to offer pages offers = response.xpath("//a[@class='href-link tile-title-text']") for offer in offers: yield response.follow(url=offer.attrib['href'], callback=self.parse_offer) # follow pagination link tmp_1 = response.xpath( "//a[@class='arrows icon-angle-right-gray icon-right-arrow']") tmp_2 = response.xpath( "//a[@class='arrows icon-right-arrow icon-angle-right-gray']") next_page = tmp_1 if 'href' in tmp_1.attrib else tmp_2 offer_date = response.xpath("//div[@class='creation-date']") parsed_date = extract_date(offer_date[len(offer_date) - 1].get()) gumtree_req = GumtreeRequirements(req) cal = Calendar() date = cal.parse(parsed_date) required_date = cal.parse(' '.join( [str(gumtree_req.number_of_days), 'days ago'])) if date < required_date: return yield response.follow(next_page.attrib['href'], self.parse)
def parse_offer(self, response): """Extracts the details of the offer to search through.""" unprocessed_date = response.css( '#wrapper > div:nth-child(1) > div.vip-header-and-details > div.vip-details' ' > ul > li:nth-child(1) > div > span.value').get() (_, unprocessed_date, _) = unprocessed_date.split('>') (processed_date, _) = unprocessed_date.split('<') gumtree_req = GumtreeRequirements(req) cal = Calendar() offer_submission_date = cal.parse(processed_date) required_date = cal.parse(' '.join( [str(gumtree_req.number_of_days), 'days ago'])) if offer_submission_date < required_date: return spans = response.xpath("//span[@class='value']").getall() spans_text = get_processed_text(spans) p = response.xpath("//span[@class='pre']").getall() p_text = get_processed_text(p) text = ' '.join([spans_text, p_text]) if calculate_intersection(text, gumtree_req.tags) >= gumtree_req.threshold: append_to_file(path='scrapy-data/urls.txt', response=response)
def parse_offer(self, response): """Extracts the details of the offer to search through.""" # Extract date of offer submission # We don't want an offer which is too old unprocessed_date = response.xpath("//div[@class='css-lh1bxu']").get() (_, _, unprocessed_date) = unprocessed_date.partition(':') (processed_date, _, _) = unprocessed_date.partition('<') cal = Calendar() offer_submission_date = cal.parse(processed_date) otodom_req = OtodomRequirements(req) required_date = cal.parse(' '.join( [str(otodom_req.number_of_days), 'days ago'])) if offer_submission_date < required_date: return li = response.xpath("//li/text()").getall() li_text = get_processed_text(li) p = response.xpath("//p/text()").getall() p_text = get_processed_text(p) text = ' '.join([li_text, p_text]) if calculate_intersection(text, otodom_req.tags) >= otodom_req.threshold: append_to_file(path='scrapy-data/urls.txt', response=response)
def parse(self, response): # follow links to offer pages offers = response.xpath('//a[@data-cy="listing-ad-title"]') for offer in offers: yield response.follow(url=offer.attrib['href'], callback=self.parse_offer) latest_date = response.xpath('//small//span//i[@data-icon="clock"]/../text()').getall().pop() olx_req = OlxRequirements(req) cal = Calendar() required_date = cal.parse(' '.join([str(olx_req.number_of_days), 'days ago']))[0] parsed_date = latest_date.replace('\n', '').replace('\t', '') latest_date_processed = olx_convert_to_time_struct(parsed_date) if latest_date_processed < required_date: return yield response.follow(url=response.xpath('//a[@data-cy="page-link-next"]').attrib['href'], callback=self.parse)
def clean(self, value): """ Validates that the input can be converted to a time. Returns a Python datetime.time object. """ super(NaturalTimeField, self).clean(value) if value in EMPTY_VALUES: return None if isinstance(value, datetime.time): return value c = Calendar() parsed = c.parse(value) if parsed[1] == 2: return datetime.time(*parsed[0][3:6]) raise ValidationError(self.error_messages['invalid'])
def str_to_datetime(string, on_fail_return=None): try: from dateutil import parser as p output = p.parse(string) return output except: from parsedatetime import Calendar from datetime import datetime c = Calendar() output, flags = c.parse(string) if flags > 0: return datetime(*output[:6]) else: return None return None
def test_olx_convert_to_time_struct_valid_case(): test_input = { 'dzisiaj 13:48': 'today 13:48', 'wczoraj 13:48': 'yesterday 13:48', '16 sty': '16 january', '16 wrz': '16 september', '16 lut': '16 february', '16 mar': '16 march', '16 kwi': '16 april', '16 maj': '16 may', '16 cze': '16 june', '16 lip': '16 july', '16 sie': '16 august', '16 paź': '16 october', '16 lis': '16 november', '16 gru': '16 december', } cal = Calendar() for k, v in test_input.items(): assert olx_convert_to_time_struct(k) == cal.parse(v)[0]
def olx_convert_to_time_struct(date_str): olx_date_mapper = { 'dzisiaj': 'today', 'wczoraj': 'yesterday', 'sty': 'january', 'wrz': 'september', 'lut': 'february', 'mar': 'march', 'kwi': 'april', 'maj': 'may', 'cze': 'june', 'lip': 'july', 'sie': 'august', 'paź': 'october', 'lis': 'november', 'gru': 'december', } for k, v in olx_date_mapper.items(): date_str = date_str.replace(k, v) cal = Calendar() return cal.parse(date_str)[0]
def parse_time( time_str: str, seconds: int = True ) -> typing.Union[None, int, typing.Tuple[datetime.datetime, int]]: """ Parses a time. :param time_str: The time string to parse. :return: The total number of seconds between now and then. """ calendar = Calendar() t_struct, parse_status = calendar.parse( time_str, sourceTime=datetime.datetime.utcnow()) if parse_status == 0: return None dt = datetime.datetime(*t_struct[:6]) diff = np.ceil((dt - datetime.datetime.utcnow()).total_seconds()) if seconds: return diff else: return dt, diff
def parse(self, response): # follow links to offer pages offers = response.xpath("//a[@class='property_link property-url']") for offer in offers: yield response.follow(url=offer.attrib['href'], callback=self.parse_offer) latest_date = response.xpath("//span[@class='single-result__category single-result__category--date']")\ .getall()\ .pop() # the strong word appears in the rag when the date is in bold (and it's only bold when the offer has just been # added, hence there is no sense in finding out whether is't an old offer if 'strong' not in latest_date: morizon_req = MorizonRequirements(req) cal = Calendar() required_date = cal.parse(' '.join([str(morizon_req.number_of_days), 'days ago'])) parsed_date = extract_from_tag(latest_date) latest_date_processed = morizon_convert_to_time_struct(parsed_date) if latest_date_processed < required_date: return yield response.follow( url=response.xpath("//a[@class='mz-pagination-number__btn mz-pagination-number__btn--next']") .pop() .attrib['href'], callback=self.parse)
def clean(self, value): """ Validates that the input can be converted to a datetime. Returns a Python datetime.datetime object. """ super(NaturalDateTimeField, self).clean(value) if value in EMPTY_VALUES: return None if isinstance(value, datetime.datetime): return value if isinstance(value, datetime.date): return datetime.datetime(value.year, value.month, value.day) if isinstance(value, list): # Input comes from a SplitDateTimeWidget, for example. So, it's two # components: date and time. if len(value) != 2: raise ValidationError(self.error_messages['invalid']) value = '%s %s' % tuple(value) c = Calendar() parsed = c.parse(value) if parsed[1] == 3: return datetime.date(*parsed[0][:6]) raise ValidationError(self.error_messages['invalid'])
soup = get_page2() scripts = soup.find_all('script') scores_script = [x.renderContents() for x in scripts if 'myScores' in x.renderContents()][0] matches = re.search('.+(\[.+?\]).+', scores_script).groups()[0] my_scores = json.loads(matches) scores = [] parser = Calendar() for mys in my_scores: if not mys['DataReceived'] == 'has-data': continue date = datetime.datetime.fromtimestamp( time.mktime( parser.parse( '{} {}'.format(mys['ChartDate'], datetime.datetime.now().year) )[0] ) ) date = date.replace(hour=0, minute=0, second=0) output = { 'date': date.isoformat(), 'events': float(mys['Events']), 'events_score': float(mys['EventsScore']), 'leak': float(mys['Leak']), 'leak_score': float(mys['LeakScore']), 'mask': float(mys['Mask']), 'mask_score': float(mys['MaskScore']), 'usage': mys['UsageDisplay'], 'usage_hours': float(mys['Usage']) if mys['Usage'] else 0, 'score': float(mys['Score'])
def execute(pagename, request, fieldname='value', titlesearch=0, statistic=0): _ = request.getText titlesearch = checkTitleSearch(request) if titlesearch < 0: check_surge_protect(request, kick=True) # get rid of spammer return advancedsearch = isAdvancedSearch(request) form = request.values # context is relevant only for full search if titlesearch: context = 0 elif advancedsearch: context = 180 # XXX: hardcoded context count for advancedsearch else: context = int(form.get('context', 0)) # Get other form parameters needle = form.get(fieldname, '') case = int(form.get('case', 0)) regex = int(form.get('regex', 0)) # no interface currently hitsFrom = int(form.get('from', 0)) highlight_titles = int(form.get('highlight_titles', 1)) highlight_pages = int(form.get('highlight_pages', 1)) mtime = None msg = '' historysearch = 0 # if advanced search is enabled we construct our own search query if advancedsearch: and_terms = form.get('and_terms', '').strip() or_terms = form.get('or_terms', '').strip() not_terms = form.get('not_terms', '').strip() #xor_terms = form.get('xor_terms', '').strip() categories = form.getlist('categories') or [''] timeframe = form.get('time', '').strip() language = form.getlist('language') or [''] mimetype = form.getlist('mimetype') or [0] excludeunderlay = form.get('excludeunderlay', 0) nosystemitems = form.get('nosystemitems', 0) historysearch = form.get('historysearch', 0) mtime = form.get('mtime', '') if mtime: mtime_parsed = None # get mtime from known date/time formats for fmt in (request.user.datetime_fmt, request.cfg.datetime_fmt, request.user.date_fmt, request.cfg.date_fmt): try: mtime_parsed = time.strptime(mtime, fmt) except ValueError: continue else: break if mtime_parsed: mtime = time.mktime(mtime_parsed) else: # didn't work, let's try parsedatetime cal = Calendar() mtime_parsed, parsed_what = cal.parse(mtime) # XXX it is unclear if usage of localtime here and in parsedatetime module is correct. # time.localtime is the SERVER's local time and of no relevance to the user (being # somewhere in the world) # mktime is reverse function for localtime, so this maybe fixes it again!? if parsed_what > 0 and mtime_parsed <= time.localtime(): mtime = time.mktime(mtime_parsed) else: mtime_parsed = None # we don't use invalid stuff # show info if mtime_parsed: # XXX mtime_msg is not shown in some cases mtime_msg = _( "(!) Only pages changed since '''%s''' are being displayed!", wiki=True) % request.user.getFormattedDateTime(mtime) else: mtime_msg = _( '/!\\ The modification date you entered was not ' 'recognized and is therefore not considered for the ' 'search results!', wiki=True) else: mtime_msg = None word_re = re.compile(r'(\"[\w\s]+"|\w+)', re.UNICODE) needle = '' if categories[0]: needle += 'category:%s ' % ','.join(categories) if language[0]: needle += 'language:%s ' % ','.join(language) if mimetype[0]: needle += 'mimetype:%s ' % ','.join(mimetype) if excludeunderlay: needle += '-domain:underlay ' if nosystemitems: needle += '-domain:system ' if and_terms: needle += '(%s) ' % and_terms if not_terms: needle += '(%s) ' % ' '.join( ['-%s' % t for t in word_re.findall(not_terms)]) if or_terms: needle += '(%s) ' % ' or '.join(word_re.findall(or_terms)) # check for sensible search term stripped = needle.strip() if len(stripped) == 0: request.theme.add_msg( _( 'Please use a more selective search term instead ' 'of {{{"%s"}}}', wiki=True) % wikiutil.escape(needle), "error") Page(request, pagename).send_page() return needle = stripped # Setup for type of search if titlesearch: title = _('Title Search: "%s"') sort = 'page_name' else: if advancedsearch: title = _('Advanced Search: "%s"') else: title = _('Full Text Search: "%s"') sort = 'weight' # search the pages from MoinMoin.search import searchPages, QueryParser, QueryError try: query = QueryParser(case=case, regex=regex, titlesearch=titlesearch).parse_query(needle) except QueryError: # catch errors in the search query request.theme.add_msg( _( 'Your search query {{{"%s"}}} is invalid. Please refer to ' 'HelpOnSearching for more information.', wiki=True, percent=True) % wikiutil.escape(needle), "error") Page(request, pagename).send_page() return results = searchPages(request, query, sort, mtime, historysearch) # directly show a single hit for title searches # this is the "quick jump" functionality if you don't remember # the pagename exactly, but just some parts of it if titlesearch and len(results.hits) == 1: page = results.hits[0] if not page.attachment: # we did not find an attachment page = Page(request, page.page_name) querydict = {} if highlight_pages: highlight = query.highlight_re() if highlight: querydict.update({'highlight': highlight}) url = page.url(request, querystr=querydict) request.http_redirect(url) return if not results.hits: # no hits? f = request.formatter querydict = wikiutil.parseQueryString(request.query_string).to_dict() querydict.update({'titlesearch': 0}) request.theme.add_msg( _( 'Your search query {{{"%s"}}} didn\'t return any results. ' 'Please change some terms and refer to HelpOnSearching for ' 'more information.%s', wiki=True, percent=True) % (wikiutil.escape(needle), titlesearch and ''.join([ '<br>', _('(!) Consider performing a', wiki=True), ' ', f.url(1, href=request.page.url(request, querydict, escape=0)), _('full-text search with your search terms'), f.url(0), '.', ]) or ''), "error") Page(request, pagename).send_page() return # This action generates data using the user language request.setContentLanguage(request.lang) request.theme.send_title(title % needle, pagename=pagename) # Start content (important for RTL support) request.write(request.formatter.startContent("content")) # Hints f = request.formatter hints = [] if titlesearch: querydict = wikiutil.parseQueryString(request.query_string).to_dict() querydict.update({'titlesearch': 0}) hints.append(''.join([ _( "(!) You're performing a title search that might not include" ' all related results of your search query in this wiki. <<BR>>', wiki=True), ' ', f.url(1, href=request.page.url(request, querydict, escape=0)), f.text( _('Click here to perform a full-text search with your ' 'search terms!')), f.url(0), ])) if advancedsearch and mtime_msg: hints.append(mtime_msg) if hints: request.write(searchHints(f, hints)) # Search stats request.write(results.stats(request, request.formatter, hitsFrom)) # Then search results info = not titlesearch if context: output = results.pageListWithContext(request, request.formatter, info=info, context=context, hitsFrom=hitsFrom, hitsInfo=1, highlight_titles=highlight_titles, highlight_pages=highlight_pages) else: output = results.pageList(request, request.formatter, info=info, hitsFrom=hitsFrom, hitsInfo=1, highlight_titles=highlight_titles, highlight_pages=highlight_pages) request.write(output) request.write(request.formatter.endContent()) request.theme.send_footer(pagename) request.theme.send_closing_html()
def morizon_convert_to_time_struct(date_str): morizon_date_mapper = {'dzisiaj': 'today', 'wczoraj': 'yesterday'} cal = Calendar() date_str = morizon_date_mapper[ date_str] if date_str in morizon_date_mapper else date_str return cal.parse(date_str)[0]
def human_time_to_datetime(s): cal = Calendar() t, _ = cal.parse(s) return datetime(*t[:6])
def fuzzydtparse(request): """ Attempts to parse a natural-language date/time string and return a formatted representation of the parsed date/time. The returned representations are formatted using django's php-style datetime formatting facilities. See http://docs.djangoproject.com/en/dev/ref/templates/builtins/#now for a full specification GET/POST arguments: dtstring *(required)* The natural-language date and/or time string to parse. dateformat (optional) A format specifier string used to format the returned representation if it is determined to be a date instance. The default format is 'l, F jS Y', which produces values like 'Thursday, October 1st 2009'. timeformat (optional) A format specifier string used to format the returned representation if it is determined to be a time instance. The default format is 'P', which produces values like '6:26 p.m.'. dtformat (optional) A format specifier string used to format the returned representation if it is determined to be a datetime instance. The default format is 'l, F jS Y, P', which produces values like 'Thursday, October 1st 2009, 6:26 p.m.'. require (optional) One of 'date', 'time', 'datetime'. If the parsed value is not of the specified type, the view will return 400/Bad Request callback (optional) JSONP callback. Returns a json dictionary containing two values: type An string indicating the kind of representation returned. One of 'date', 'time', or 'datetime' parsed A string representation of the parsed datetime. Invalid / unparsable datetimes will return 400/Bad Request. """ try: dtstring = request.REQUEST['dtstring'] except KeyError: return HttpResponseBadRequest() kind = { 'date': 1, 'time': 2, 'datetime': 3 } dateformat = request.REQUEST.get('dateformat', 'l, F jS Y' ) timeformat = request.REQUEST.get('timeformat', 'P') dtformat = request.REQUEST.get('dtformat', 'l, F jS Y, P') require = request.REQUEST.get('require', None) callback = request.REQUEST.get('callback', None) if require and require not in kind: return HttpResponseBadRequest() c = Calendar() # TODO: possible security hole? parsed = c.parse(dtstring) if parsed[1] == 0: return HttpResponseBadRequest() parsed_dt = datetime.datetime(*parsed[0][:6]) response_dict = {} if require and parsed[1] != kind[require]: return HttpResponseBadRequest() try: if parsed[1] == 1: response_dict['type'] = 'date' response_dict['parsed'] = format(parsed_dt, dateformat) elif parsed[1] == 2: response_dict['type'] = 'time' response_dict['parsed'] = format(parsed_dt, timeformat) elif parsed[1] == 3: response_dict['type'] = 'datetime' response_dict['parsed'] = format(parsed_dt, dtformat) else: #should never be here return HttpResponseBadRequest() except: return HttpResponseBadRequest() if callback: resp = "%s(%s)" % (callback, json.dumps(response_dict)) else: resp = json.dumps(response_dict) return HttpResponse(resp, mimetype='application/javascript')
def parse_message(text): c = Calendar() t_s, p_s = c.parse(text) time = datetime(*t_s[:6]) td = time - datetime.now() return None if td.days < 0 else td.total_seconds()
print("relative time (for example, '5 minutes' or 'tomorrow') or an") print("actual time (for example, '8am').") if error is not None: print("\n\n") print (error) sys.exit(1) if len(sys.argv) == 1: helptext() from parsedatetime import Calendar from time import mktime, sleep from datetime import datetime, timedelta p = Calendar() specifiedtime = p.parse(" ".join(sys.argv[1:])) timeleft = datetime.fromtimestamp(mktime(specifiedtime[0])) - datetime.now() length = 0 while timeleft > timedelta(microseconds=-1): interval = 10 if timeleft < timedelta(hours=1): interval = 1 if timeleft < timedelta(minutes=10): interval = 0.1 if timeleft < timedelta(minutes=1): interval = 0.001 sys.stdout.write("\b" * length) outline = str(timeleft) length = len(outline)
print("actual time (for example, '8am').") if error is not None: print("\n\n") print(error) sys.exit(1) if len(sys.argv) == 1: helptext() from parsedatetime import Calendar from time import mktime, sleep from datetime import datetime, timedelta p = Calendar() specifiedtime = p.parse(" ".join(sys.argv[1:])) timeleft = datetime.fromtimestamp(mktime(specifiedtime[0])) - datetime.now() length = 0 while timeleft > timedelta(microseconds=-1): interval = 10 if timeleft < timedelta(hours=1): interval = 1 if timeleft < timedelta(minutes=10): interval = 0.1 if timeleft < timedelta(minutes=1): interval = 0.001 sys.stdout.write("\b" * length) outline = str(timeleft) length = len(outline)
def fuzzydtparse(request): """ Attempts to parse a natural-language date/time string and return a formatted representation of the parsed date/time. The returned representations are formatted using django's php-style datetime formatting facilities. See http://docs.djangoproject.com/en/dev/ref/templates/builtins/#now for a full specification GET/POST arguments: dtstring *(required)* The natural-language date and/or time string to parse. dateformat (optional) A format specifier string used to format the returned representation if it is determined to be a date instance. The default format is 'l, F jS Y', which produces values like 'Thursday, October 1st 2009'. timeformat (optional) A format specifier string used to format the returned representation if it is determined to be a time instance. The default format is 'P', which produces values like '6:26 p.m.'. dtformat (optional) A format specifier string used to format the returned representation if it is determined to be a datetime instance. The default format is 'l, F jS Y, P', which produces values like 'Thursday, October 1st 2009, 6:26 p.m.'. require (optional) One of 'date', 'time', 'datetime'. If the parsed value is not of the specified type, the view will return 400/Bad Request callback (optional) JSONP callback. Returns a json dictionary containing two values: type An string indicating the kind of representation returned. One of 'date', 'time', or 'datetime' parsed A string representation of the parsed datetime. Invalid / unparsable datetimes will return 400/Bad Request. """ try: dtstring = request.REQUEST['dtstring'] except KeyError: return HttpResponseBadRequest() kind = {'date': 1, 'time': 2, 'datetime': 3} dateformat = request.REQUEST.get('dateformat', 'l, F jS Y') timeformat = request.REQUEST.get('timeformat', 'P') dtformat = request.REQUEST.get('dtformat', 'l, F jS Y, P') require = request.REQUEST.get('require', None) callback = request.REQUEST.get('callback', None) if require and require not in kind: return HttpResponseBadRequest() c = Calendar() # TODO: possible security hole? parsed = c.parse(dtstring) if parsed[1] == 0: return HttpResponseBadRequest() parsed_dt = datetime.datetime(*parsed[0][:6]) response_dict = {} if require and parsed[1] != kind[require]: return HttpResponseBadRequest() try: if parsed[1] == 1: response_dict['type'] = 'date' response_dict['parsed'] = format(parsed_dt, dateformat) elif parsed[1] == 2: response_dict['type'] = 'time' response_dict['parsed'] = format(parsed_dt, timeformat) elif parsed[1] == 3: response_dict['type'] = 'datetime' response_dict['parsed'] = format(parsed_dt, dtformat) else: #should never be here return HttpResponseBadRequest() except: return HttpResponseBadRequest() if callback: resp = "%s(%s)" % (callback, json.dumps(response_dict)) else: resp = json.dumps(response_dict) return HttpResponse(resp, mimetype='application/javascript')
def __init__(self): self.parser.add_argument('-s', '--status', action='store_true', help='show rule list with expirations') self.parser.add_argument('-c', '--clean', action='store_true', help='clean up expired rules') self.parser.add_argument('-r', '--rule', help='rule to be added to `ufw`') self.parser.add_argument('-p', '--position', default=1, help='position to add the rule') self.parser.add_argument('-t', '--ttl', default='30 days', help='time to live for the rule') args = self.parser.parse_args() # Our file names pid_file = '/var/run/' + __file__ + '.pid' rules_file = '/usr/local/share/' + __file__ + '/rules' tmp_rules_file = '/tmp/' + __file__ + '-rules' if args.status: if path.exists(rules_file): try: print("Expiration\t\tRule") print('=' * 80) # Loops through the rules lines for line in open(rules_file, 'r'): # Breaks apart line into expiration timestamp and rule timestamp, rule = line.strip("\n").split(' ', 1) print( str(datetime.fromtimestamp(float(timestamp))) + "\t" + rule) except IOError: self.error('unable to read from the rules file: ' + rules_file) else: self.error('there are no rules to display') elif args.clean: # Checks for PID file if path.exists(pid_file): self.error(__file__ + ' is already running') else: # Creates the PID file try: handle = open(pid_file, 'w') handle.write(str(getpid())) handle.close() except IOError: self.error('unable to create PID file: ' + pid_file) # Checks for the rules file if path.exists(rules_file): # Opens the temporary rules file try: handle = open(tmp_rules_file, 'a') except IOError: self.error('unable to write to the tmp rules file: ' + tmp_rules_file) try: current_time = time() # Loops through the rules lines for line in open(rules_file, 'r'): # Breaks apart line into expiration timestamp and rule timestamp, rule = line.strip("\n").split(' ', 1) # Checks if rule has expired if current_time < float(timestamp): handle.write(line) print( str(datetime.fromtimestamp(time())) + "\tskipped rule\t" + rule) else: try: self.ufw_execute('delete ' + rule) print( str(datetime.fromtimestamp(time())) + "\tdeleted rule\t" + rule) except CalledProcessError as error: self.ufw_error(error) handle.close() # Moves the tmp file to the rules file move(tmp_rules_file, rules_file) except IOError: self.error('unable to from the read rules file: ' + rules_file) # Removes the PID remove(pid_file) elif args.rule: rules_path = path.dirname(rules_file) if not path.exists(rules_path): makedirs(rules_path) # Converts the TTL to a timestamp cal = Calendar() timestamp = mktime(cal.parse(args.ttl)[0]) # Writes the rule to the rules file try: # TODO Check if rule already exists and update it instead of adding it again handle = open(rules_file, 'a') handle.write(str(timestamp) + ' ' + args.rule) handle.write("\n") handle.close() except IOError: self.error('unable to write to the rules file: ' + rules_file) # Attempts to add the rule to `ufw` try: self.ufw_execute('insert ' + str(args.position) + ' ' + args.rule) except CalledProcessError as error: # Catches an error when attempting to add a rule to an empty database if error.output == b"ERROR: Invalid position '1'\n": try: self.ufw_execute(args.rule) except CalledProcessError as error: self.ufw_error(error) else: self.ufw_error(error) else: self.error('no arguments specified')
def str_ftime(arg, format): cal = Calendar() return strftime(format, cal.parse(str(arg))[0])
class Giveaway(commands.Cog): def __init__(self, bot): self.bot = bot self.time_parser = Calendar() self.min_time = 5 self.bold = re.compile(r'(\d+)') async def prompt(self, ctx, prompt: str): await ctx.send(prompt) def check(m): return m.channel.id == ctx.channel.id and m.author.id == ctx.author.id try: msg = await self.bot.wait_for('message', timeout=420, check=check) except asyncio.TimeoutError: embed = discord.Embed( title='Timeout', descripton='You took too long to respond to my prompt. ' 'Please restart the command and try again.' ) await ctx.send(embed=embed) return None return msg.content async def create_giveaway(self, ctx, prize, channel, total_time, winners, desc, req_int, role_reqs, invite, req_text, emoji): ts = int(time.time() + total_time) final_req_text = '' req = req_text if req: final_req_text += req else: if role_reqs: if req_int: req_text += '\U0001f4dd __Must have any of the following roles:__ ' else: req_text += '\U0001f4dd __Must have all of the following roles:__ ' req_text += ', '.join(role.mention for role in role_reqs) if invite: req_text += f'\n\U0001f4dd __Must be in the server:__ ' \ f'[**{invite.guild.name}**]({invite})' final_req_text = final_req_text or 'No requirements' s = '' if winners == 1 else 's' embed = discord.Embed( title=prize, description=desc, color=discord.Colour.dark_orange(), timestamp=datetime.utcfromtimestamp(ts) ).add_field( name='\U0001f60e Requirements:', value=final_req_text, inline=False ).add_field( name='\u23f0 Ends In:', value=self.bold.sub(r'**\1**', precisedelta(total_time)), inline=False ).add_field( name='\U0001f451 Host:', value=ctx.author.mention, inline=False ).set_author( name='New Giveaway!', icon_url=self.bot.get_icon(ctx.guild) ).set_footer( text=str(winners) + f' Winner{s} | Ending at ->' ) msg = await channel.send(embed=embed) await msg.add_reaction(emoji) role_ids = [role.id for role in role_reqs] query = '''INSERT INTO giveaways ( guild_id, channel_id, message_id, embed, prize, winners_num, role_req, role_req_type, guild_req, ends_at, ended ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) ''' ended = False if total_time > 30 else True dumped = json.dumps(msg.embeds[0].to_dict(), indent=4) values = (ctx.guild.id, channel.id, msg.id, dumped, prize, winners, role_ids, req_int, invite.guild.id if invite else None, ts, ended) self.bot.message_ids.append(msg.id) await self.bot.db.execute(query, *values) ping = discord.utils.find(lambda r: 'giveaway ping' in r.name.lower(), ctx.guild.roles) if ping: msg = await channel.send(ping.mention) await msg.delete() if ctx.channel.id != channel.id: await ctx.send('Giveaway created!') if total_time < 30: await end(self.bot, ts, msg.id, channel.id, dumped) @commands.command(aliases=['create']) @is_giveaway_manager() async def giveaway(self, ctx): channel = await self.prompt(ctx, 'What channel is this giveaway in?') try: channel = await commands.TextChannelConverter().convert(ctx, channel) except commands.ChannelNotFound: return await ctx.send('Invalid channel.') prize = await self.prompt(ctx, 'What are you giving away?') if not prize: return winners = await self.prompt(ctx, 'How many winners will there be?') if not winners: return try: winners = int(winners) except ValueError: return await ctx.send('Invalid number.') if winners < 1: return await ctx.send('Must be greater than 1.') t = await self.prompt(ctx, 'How long will the giveaway last?') if not t: return parsed = self.time_parser.parse(t) ts = time.mktime(parsed[0]) total = int(ts - time.time()) if not total: return await ctx.send('Invalid time.') desc = await self.prompt(ctx, 'Enter a description for this giveaway (150 chars max) ' 'or type `skip`.') if not desc: return while len(desc) > 150: desc = await self.prompt(ctx, 'Not under 150 characters. Try again.') if not desc: return if desc.lower() == 'skip': desc = '' roles = await self.prompt(ctx, 'What are the role requirements to enter? ' 'Enter comma-separated role names/IDs/mentions. ' 'Type `skip` for no role requirements.') if not roles: return role_reqs = [] req_int = 0 if roles.lower() != 'skip': rc = commands.RoleConverter() roles = roles.replace(', ', ',').split(',') for role in roles: try: role_reqs.append(await rc.convert(ctx, role)) except commands.RoleNotFound as err: return await ctx.send(f'`{err.argument}` is not a valid role. Try again.') req_type = await self.prompt(ctx, 'Does the user need **all** the roles to enter, ' 'or **any** of the roles to enter? ' 'Respond with `all` or `any`.') if not req_type: return if req_type.lower() == 'all': req_int = 0 elif req_type.lower() == 'any': req_int = 1 else: return await ctx.send('Not a valid option.') invite_obj = None invite = await self.prompt(ctx, 'What server does this user have to be in ' 'to enter the giveaway? Enter a **permanent ' 'invite link that has infinite uses** or type ' '`skip`.') if not invite: return if invite.lower() != 'skip': ic = commands.InviteConverter() try: invite = await ic.convert(ctx, invite) except commands.BadInviteArgument: return await ctx.send(f'`{invite}` was not a valid invite.') if invite.max_uses or invite.max_age: return await ctx.send('The invite provided is not permanent ' 'and does not have infinite usage.') if isinstance(invite, discord.PartialInviteGuild): return await ctx.send('I am not in the server with that invite.') in_guild = invite.guild.get_member(ctx.author.id) if not in_guild: return await ctx.send('You must also be in that server to ' 'set it as a requirement.') invite_obj = invite req_text = await self.prompt(ctx, 'Enter a manual requirement text, ' 'or type `skip`.') if not req_text: return if req_text.lower() == 'skip': req_text = '' emoji = await self.prompt(ctx, 'Enter an emoji that will be reacted for entering, ' 'or type `skip` for the default :tada:') if not emoji: return if emoji.lower() == 'skip': emoji = '\U0001f389' else: try: emoji = await EmojiConverter().convert(ctx, emoji) except commands.EmojiNotFound: return await ctx.send(f'`{emoji}` was not a valid emoji. ' "Make sure I am also in the emoji's server") await self.create_giveaway(ctx, prize, channel, total, winners, desc, req_int, role_reqs, invite_obj, req_text, emoji)
def convert_date(raw_date: str) -> str: parser = Calendar() date, status = parser.parse(raw_date) date = datetime(*date[:3]) return date.strftime("%Y-%m-%d")