def __init__(self, body, tags, title='', isStatus=True, visible=False): self.published = datetime.utcnow() self.title = title self.body = body self.tags = tags if self.title: self.slug = slugify(self.published, title) else: self.slug = slugify(self.published, body[:15]) self.isStatus = isStatus self.visible = visible
def test_create_article(client: FlaskClient, user_client: FlaskClient, stuff_client: FlaskClient, app: Flask, title: str, abstract: str, content: str, status_code: int) -> None: url = "/articles" data = { "title": title, "abstract": abstract, "content": content, } res = client.post(url, json=data) assert res.status_code == 401 res = user_client.post(url, json=data) assert res.status_code == 403 res = stuff_client.post(url, json=data) assert res.status_code == status_code if status_code == 400: return res = stuff_client.post(url, json=data) assert res.status_code == 400 with app.app_context(): article = Article.query.filter_by(title=title).first() assert article assert article.slug == slugify(article.title) assert article.abstract == abstract assert article.content == content assert article.author
def validate_title(title): if len(title) < 1: message = ( 'Title is too short, needs to be at least 1 character long.' ) raise InvalidUsage(message) # two or more posts can not exist on the same date with the same title # because of the slug slug = slugify(datetime.utcnow(), title) if Post.query.filter_by(slug=slug).first(): message = 'Title already exist on this date.' raise InvalidUsage(message, 409)
def test_update_article_detail(client: FlaskClient, user_client: FlaskClient, stuff_client: FlaskClient, app: Flask, data: dict) -> None: url = "/articles/{}" article = create_article(app) res = client.put(url.format(article.slug), json=data) assert res.status_code == 401 res = user_client.put(url.format(article.slug), json=data) assert res.status_code == 403 res = stuff_client.put(url.format(article.slug), json=data) assert res.status_code == 200 with app.app_context(): article = Article.query.filter_by(title=data.get("title")).first() update_fields = ["title", "abstract", "content"] for field in update_fields: if field in data: assert getattr(article, field) == data.get(field) assert article.slug == slugify(article.title)
def test_update_category_detail(client: FlaskClient, user_client: FlaskClient, stuff_client: FlaskClient, app: Flask, data: dict) -> None: url = "/categories/{}" category = create_category(app) res = client.put(url.format(category.slug), json=data) assert res.status_code == 401 res = user_client.put(url.format(category.slug), json=data) assert res.status_code == 403 res = stuff_client.put(url.format(category.slug), json=data) assert res.status_code == 200 if not data.get("name"): return with app.app_context(): category = Category.query.filter_by(name=data.get("name")).first() assert category.name == data.get("name") assert category.slug == slugify(category.name)
def test_create_category(client: FlaskClient, user_client: FlaskClient, stuff_client: FlaskClient, app: Flask, name: str, status_code: int) -> None: url = "/categories" data = {"name": name} res = client.post(url, json=data) assert res.status_code == 401 res = user_client.post(url, json=data) assert res.status_code == 403 res = stuff_client.post(url, json=data) assert res.status_code == status_code with app.app_context(): category = Category.query.filter_by(name=name).first() if status_code == 400: return res = stuff_client.post(url, json=data) assert res.status_code == 400 assert category assert category.slug == slugify(name)
def save(self, *args, **kwargs): self.slug = slugify(self.name, instance=self) super(Subscription, self).save(*args, **kwargs)
def standings_helper(url, league, skip_conference_row=False): """ Fetches and parses data. Supports layouts with multiple tables or with single tables. At the time of writing this, the MLB standings is split into 2 tables, while the NHL is 1. :param league: The league of the desired scoreboard :type league: str :returns: A formatted dictionary ready for display :rtype: dict """ rv = fetch_cached_data() if rv is not None: return rv soup = help_fetch_soup(url) column_list = [] row_list = [] stack = {} # Iterate over each conference/league for table in soup("table"): conference = None division = None # Iterate over each division for row in table("tr"): if row.get("class") is None: continue elif "shsTableTtlRow" in row.get("class"): if skip_conference_row: continue # Single table layout support. # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # If the string conference evaluates to true, then we've # encountered a new conference. Save the data that # exists in the lists column_list and row_list if conference: # Does the list colum_stack have any data? if column_list: # Is this layout split into divisions? if division: row_list.append( { division : column_list } ) else: row_list = column_list column_list = [] stack[conference] = row_list row_list = [] conference = row.extract().text.strip().lower().encode("utf-8") conference = slugify(text=unicode(conference, "utf-8"), delimiter=u'_') elif "shsTableSubttlRow" in row.get("class"): # If the string division evaluates to true, then we've # encountered a new division. Save the data that # exists in the lists column_list and row_list if division: # Does the list colum_stack have any data? if column_list: # Is this layout split into divisions? if division: row_list.append( { division : column_list } ) else: row_list.append(column_list) column_list = [] division = row.extract().text.strip().lower().encode("utf-8") division = division.replace("division", '') division = slugify(text=unicode(division, "utf-8"), delimiter=u'_') elif any(css_class.startswith("shsRow") for css_class in row.get("class")): cells = row("td") value_dict = None if "mlb" == league: value_dict = help_parse_mlb_soup(cells) elif "nhl" == league: value_dict = help_parse_nhl_soup(cells) elif "nfl" == league: value_dict = help_parse_nfl_soup(cells) elif "nba" == league: value_dict = help_parse_nba_soup(cells) elif "mls" == league: value_dict = help_parse_mls_soup(cells) elif "epl" == league: value_dict = help_parse_epl_soup(cells) if value_dict is not None: column_list.append(value_dict) #end for row in table("tr") # Get the last division in the table if division: row_list.append( { division : column_list } ) # If there is no division, then make the columns close to the # conference else: row_list = column_list column_list = [] # We must evaluate conference because EPL and MLS do not have # conferences if conference: stack[conference] = row_list # If a conference is nonexistent, then check for division's # existence. If a division exists, then treat as if it was a # conference (i.e. place the division at the highest level). # Currently, this only occurs with MLS. elif division: if row_list[0][division]: stack[division] = row_list[0][division] # Otherwise, both conference and division are nonexistent. # Convert stack into a list so the teams are ordered # accordingly. # Currently, this only occurs with EPL. else: # stack is a Dictionary, change it to a list del stack stack = row_list row_list = [] #end for table in soup("table") out = prepare_json_output(stack) del row_list, stack # Cache for 2 hours cache_data(data=out, timeout=60 * 60 * 2) return out
def _slugify(string): if not string: return '' return utils.slugify(string)
def scores_helper(year=None, month=None, day=None, sport=None, league=None): """ Generic helper function to scrape scoring data from STATS's JavaScript file. :param year: The year of the desired scoreboard :type year: int :param month: The month of the desired scoreboard :type month: int :param day: The day of the desired scoreboard :type day: int :param sport: The sport of the desired scoreboard :type sport: str :param league: The league of the desired scoreboard :type league: str :returns: A formatted dictionary ready for display :rtype: dict """ try: date_string = stats_date_string(date(year, month, day)) except (ValueError, TypeError): date_string = stats_date_string() rv = fetch_cached_data() if rv is not None: return rv args = { PARAM_SPORT : sport, PARAM_DATE : date_string, PARAM_LEAGUE : league } soup = help_fetch_soup( SCORES_URL, request_params=args, source_file_type="JavaScript", class_attrs="shsTable" ) # If there is 1 or 0 rows in the document, then, there are probably # no scores listed. if len(soup("tr")) <= 2: # del soup # Cache for a day to be safe out = {"message" : "No games scheduled for "} if not month and not day and not year: out["message"] += "today" else: out["message"] += "{month}/{day}/{year}".format(month=month, day=day, year=year) cache_data(data=out, timeout=60 * 60 * 24) return out stack = {} vals = [] section = '' team = None has_the_status_cell = False # logcat(str(soup)) for row in soup("tr"): # Rows which have team names do not have . # This test must be first. if row.get("class") is None: cells = row("td") has_the_status_cell = False # Does this row have a status row? if any(css_class in "shsMiniStatus" for cell in cells for css_class in cell.get("class") ): has_the_status_cell = True if len(cells) >= 2: team = "home" if team is "away" or None else "away" # If the list of values is empty, then initialize it if not vals: vals.append({"away": None, "home":None}) # If the list is complete, then append a new item # indicating a new game. elif vals[-1]["away"] and vals[-1]["home"]: vals.append({"away": None, "home":None}) # Add scoring information for the game. vals[-1][team] = { "team": cells[0].find('a').extract().text.strip().encode("utf-8"), "score": cells[1].extract().text.strip().encode("utf-8") } try: # Try to convert the string to an int. vals[-1][team]["score"] = int(vals[-1][team]["score"]) except (ValueError, TypeError): # If it fails, assign null vals[-1][team]["score"] = None if has_the_status_cell: status = cells[2].find('a') # Arbitrary game information, such as "OT" for # overtime extra = cells[2].find('br') time = cells[2].find(name="span", attrs={"class" : "shsTimezone shsGMTZone"}) # Set the status only if not null if status: vals[-1]["status"] = status.extract().text.strip().encode("utf-8") if 2 == len(vals[-1]["status"].split('-')): # Save the string to the right of '-' in # extra if not extra: extra = vals[-1]["status"].split('-')[1].strip() vals[-1]["status"] = vals[-1]["status"].split('-')[0].strip() vals[-1]["status"] = vals[-1]["status"].lower() if time: vals[-1]["time"] = time.extract().text.strip().encode("utf-8") if extra: # Sometimes, extra contains a NavigableString try: vals[-1]["extra"] = extra.extract().text.strip().encode("utf-8") # While other times, it's just a str except: vals[-1]["extra"] = extra vals[-1]["extra"] = vals[-1]["extra"].lower() # Skip over the first line, it's the title elif "shsTableTtlRow" in row.get("class"): continue elif any(css_class in "shsTableSubttlRow shsSubSectionRow shsMiniRowSpacer" for css_class in row.get("class")): cell = row("td") section = cell[0].extract().text.strip().encode("utf-8") # Are the scores separated into sections? If so, find the # separator if section: section = slugify(text=unicode(section, "utf-8"), delimiter=u'_') if vals: stack[section] = vals vals = [] # return section stack[section] = None # Save the last value else: if section: stack[section] = vals else: stack = vals del vals out = prepare_json_output(stack) # Cache for 1 minute cache_data(data=out, timeout=60) return out
def on_model_change(self, form, instance, is_created): instance.slug = utils.slugify(form.title.data) super(EventAdmin, self).on_model_change(form, instance, is_created)
def format_division(nav_str): division = nav_str.extract().text.strip().lower().encode("utf-8") division = sub(r"(conference|divisi?on|league|football)\s?", '', division) division = slugify(text=unicode(division, "utf-8"), delimiter=u'_') return division
def test_slugify(): s = "test test test" assert " " not in slugify(s) s = "测试 测试 测试" assert " " not in slugify(s)
def update_slug(self) -> None: self.slug = slugify(self.title)
def update_slug(self) -> None: self.slug = slugify(self.name)