Model API

This API layer provides access to the higher-level objects stored in Github repositories. A single Github repository serves as the persistent storage for the CMS. All data is fetched from Github through the Remote API layer and turned into formal objects by this model layer.

Article

Article related model API

class pskb_website.models.article.Article(title, author_name, filename='article.md', repo_path=None, branch=u'master', stacks=None, sha=None, content=None, external_url=None, image_url=None, author_real_name=None)[source]

Object representing article

contributors

List of tuples representing any ‘author’ i.e user who has contributed at least 1 line of text to this article. Each tuple is in the form of (name, login) where name can be None.

We use plain tuples instead of named tuples or User objects so we can easily seralize the contributors to JSON.

NOTE: This property automatically removes users set to ignore via the contributors_to_ignore() function! To get the full list use _read_contributors_from_api(remove_ignored_users=False).

static from_json(str_)[source]

Create article object from json string

Parameters:str – json string representing article
Returns:Article object
full_path

Get full path to article including repo information :returns: Full path to article

heart_count

Read number of hearts for article

Returns:Number of hearts
open_graph_image_url

Get full URL suitable for open graph meta tags

stack_image_url

Get path to static image for article based on stack

None will be returned for articles without a stack image FB open graph meta tags.

pskb_website.models.article.articles_from_json(json_str)[source]

Generator to iterate through list of article objects in json format

Parameters:json_str – JSON string
Returns:Generator through article objects
pskb_website.models.article.author_stats(statuses=None)[source]

Get number of articles for each author

Parameters:
  • statuses – List of statuses to aggregate stats for
  • statuses – Optional status to aggregate stats for, all possible statuses are counted if None is given
Returns:

Dictionary mapping author names to number of articles:

{author_name: [article_count, avatar_url]}

Note avatar_url can be None and is considered optional

pskb_website.models.article.branch_article(article, message, new_content, author_name, email, image_url, author_real_name=None)[source]

Create branch for article with new article contents

Parameters:
  • article – Article object to branch
  • message – Message describing article suggestions/changes
  • new_content – New article text
  • author_name – Name of author for article changes
  • email – Email of author for article changes
  • image_url – Image to use for article
  • author_real_name – Optional real name of author, not username
Returns:

New article object

New branch will be named after author of changes and title

pskb_website.models.article.branch_or_save_article(title, path, message, content, author_name, email, sha, image_url, repo_path=None, author_real_name=None, stacks=None, first_commit=None)[source]

Save article as original or as a branch depending on if given author is the same as original article (if it already exists)

Parameters:
  • title – Title of article
  • path – Short path to article, not including repo or owner, or empty for a new article
  • message – Commit message to save article with
  • content – Content of article
  • author_name – Name of author who wrote content
  • email – Email address of author
  • sha – Optional SHA of article if it already exists on github
  • branch – Name of branch to commit file to (branch must already exist)
  • image_url – Image to use for article
  • repo_path – Optional repo path to save into (<owner>/<name>)
  • author_real_name – Optional real name of author, not username
  • stacks – Optional list of stacks to associate with article (this argument is ignored if article is branched)
  • first_commit – SHA of first commit to save with article
Returns:

Article object updated, saved, or branched

pskb_website.models.article.change_article_stack(orig_path, orig_stack, new_stack, title, author_name, email)[source]

Change article stack

Parameters:
  • orig_path – Current path to article without repo or owner
  • orig_stack – Original stack
  • new_stack – New stack
  • author_name – Name of author who wrote article
  • email – Email address of author
Returns:

New path of article or None if error

Note this function only makes changes to articles on the master branch!

pskb_website.models.article.delete_article(article, message, name, email)[source]

Delete article from repository

Parameters:
  • article – Article object to remove
  • message – Message to include as commit when removing article
  • name – Name of user deleting article
  • email – Email address of user deleting article
Returns:

True if article was successfully removed or False otherwise

This removes the article from the repository but not the history of the file.

Only original author can remove file from master branch. Articles can be removed from non-master branches only by the user who created that branch.

pskb_website.models.article.delete_branch(article, branch_to_delete)[source]

Delete branch of guide and save to github

Parameters:
  • article – Article object to delete branch from
  • branch_to_delete – Branch of guide to delete
Returns:

True if deleted or False otherwise

pskb_website.models.article.find_article_by_title(articles, title)[source]

Search through list of article objects looking for article with given title

Parameters:
  • articles – List of article objects
  • title – Title to search for
Returns:

article object or None if not found

pskb_website.models.article.get_articles_for_author(author_name, status=None)[source]

Get iterator for articles from given author

Parameters:
  • author_name – Name of author to find articles for
  • status – PUBLISHED, IN_REVIEW, DRAFT, or None to read all articles
Returns:

Iterator through article objects

pskb_website.models.article.get_available_articles(status=None, repo_path=None)[source]

Get iterator for current article objects

Parameters:
  • status – PUBLISHED, IN_REVIEW, DRAFT, or None to read all articles
  • repo_path – Optional repo path to read from (<owner>/<name>)
Returns:

Iterator through article objects

Note that article objects only have path, title, author name, and stacks filled out. You’ll need to call read_article() to get full article details.

pskb_website.models.article.get_available_articles_from_api(status=None, repo_path=None)[source]

Get iterator for current article objects

Parameters:
  • status – PUBLISHED, IN_REVIEW, DRAFT, or None to read all articles
  • repo_path – Optional repo path to read from (<owner>/<name>)
Returns:

Iterator through article objects

Note that article objects only have path, title and author name filled out. You’ll need to call read_article() to get full article details.

pskb_website.models.article.get_public_articles_for_author(author_name)[source]

Get iterator for all public i.e. non-draft articles from given author

Parameters:author_name – Name of author to find articles for
Returns:Iterator through article objects
pskb_website.models.article.group_articles_by_status(articles)[source]

Group articles by publish status

Parameters:articles – Iterable of Article objects
Returns:Iterable like itertools.groupby with a key as the publish_status and a list of articles for that status
pskb_website.models.article.meta_data_path_for_article_path(full_path)[source]

Get path to meta data file for given article path

Parameters:full_path – Article object
Returns:Full path to meta data file for article
pskb_website.models.article.parse_full_path(path)[source]

Parse full path and return tuple of details embedded in path

Parameters:path – Full path to file including repo and owner
Returns:path_details tuple
class pskb_website.models.article.path_details(repo, filename)
filename

Alias for field number 1

repo

Alias for field number 0

pskb_website.models.article.read_article(path, rendered_text=False, branch=u'master', repo_path=None, allow_missing=False, cache_timeout=7200)[source]

Read article

Parameters:
  • path – Short path to article, not including repo or owner
  • rendered_text – Boolean to read rendered or raw text
  • branch – Name of branch to read file from
  • repo_path – Optional repo path to read from (<owner>/<name>)
  • allow_missing – False to log warning for missing or True to allow it i.e. when you’re just seeing if an article exists
  • cache_timeout – Number of seconds to keep guide in cache if cached
Returns:

Article object

pskb_website.models.article.read_article_from_metadata(file_details)[source]

Read article object from json metadata

Parameters:file_details – remote.file_details object
Returns:Article object with metadata filled out or None

Note the article contents are NOT filled out here!

pskb_website.models.article.read_meta_data_for_article_path(full_path)[source]

Read meta data for given article path from master branch

Parameters:full_path – Full path to article
Returns:Meta-data for article as json

Always read meta data from master branch because metadata is never altered or updated in branches to keep merging simple.

pskb_website.models.article.save_article(title, message, new_content, author_name, email, sha, branch=u'master', image_url=None, repo_path=None, author_real_name=None, stacks=None, status=u'draft', first_commit=None)[source]

Create or save new (original) article, not branched article

Parameters:
  • title – Title of article
  • message – Commit message to save article with
  • content – Content of article
  • author_name – Name of author who wrote article
  • email – Email address of author
  • sha – Optional SHA of article if it already exists on github (This must be the SHA of the current version of the article that is being replaced.)
  • branch – Name of branch to commit file to (branch must already exist)
  • image_url – Image to use for article
  • repo_path – Optional repo path to save into (<owner>/<name>)
  • author_real_name – Optional real name of author, not username
  • stacks – Optional list of stacks to associate with article
  • status – PUBLISHED, IN_REVIEW, or DRAFT
  • first_commit – Optional first commit of article if it already exists
Returns:

Article object updated or saved or None for failure

This function is not suitable for saving branched articles. The article created here will be attributed to the given author_name whereas branched articles should be created with branch_article() so the correct author information is maintained.

pskb_website.models.article.save_article_meta_data(article, author_name=None, email=None, branch=None, update_branches=True)[source]
Parameters:
  • article – Article object
  • author_name – Name of author who wrote article (optional)
  • email – Email address of author (optional)
  • branch – Optional branch to save metadata, if not given article.branch will be used
  • update_branches – Optional boolean to update the metadata branches of the article with the given branch (True) or to save article branches as-is (False)
Returns:

SHA of commit or None if commit failed

Note that author_name and email can be None if the site ‘admin’ is changing the meta data. However, author_name and email must both exist or both be None.

pskb_website.models.article.save_branched_article_meta_data(article, author_name, email, add_branch=True)[source]

Save metadata for branched article

Parameters:
  • article – Article object with branch attribute set to branch name
  • name – Name of author who wrote branched article
  • email – Email address of branched article author
  • add_branch – True if article should be saved as a branch False if article should be removed as a branch
Returns:

SHA of commit or None if commit failed

Metadata for branched articles should be identical to the original article. This makes it easier for automatically merging changes because metadata differences won’t get in the way. The author_name is the only thing useful for a branched article. However, that should already be encoded in the branch name and the commits. So, editors of original articles will get credit for helping via those mechanisms, not metadata.

pskb_website.models.article.search_for_article(title, stacks=None, status=None)[source]

Search for an article by the title and optionally stack and status

Parameters:
  • title – Title of article to search for
  • stacks – Optional list of stacks to search All stacks are searched if None is given
  • status – Optional status to search for All possible statuses are searched if None is given
Returns:

Article object if found or None if not found

User

User related model code

class pskb_website.models.user.User(name, login)[source]

Object representing user

static from_json(str_)[source]

Create user object from json string

Parameters:str – json string representing user
Returns:User object
is_collaborator

Determine if user is a collaborator on repo

Parameters:
  • owner – Owner of repository defaults to REPO_OWNER config value
  • repo – Name of repository defaults to REPO_NAME config value
pskb_website.models.user.find_user(username=None)[source]

Find a user object with given username

Parameters:username – Optional username to search for, if no username given the currently logged in user will be returned (if any)
Returns:User object

Note the email field on the returned user object is only valid when reading the logged in user (i.e. when NOT passing a username). We cannot read email information for users who have not authenticated the application.

File

More direct wrapper around reading files from remote storage

This module serves as a way to read and parse common markdown file ‘types’ from the repository such as the file listings for published articles, etc.

pskb_website.models.file.draft_article_path()[source]

Get path to draft article file listing

Returns:Path to draft article file listing file
pskb_website.models.file.draft_articles(branch=u'master')[source]

Get iterator through list of draft articles from file listing

Parameters:branch – Name of branch to save file listing to
Returns:Generator to iterate through file_listing_item tuples
class pskb_website.models.file.file_listing_item(title, url, author_name, author_real_name, author_img_url, thumbnail_url, stacks)
author_img_url

Alias for field number 4

author_name

Alias for field number 2

author_real_name

Alias for field number 3

stacks

Alias for field number 6

thumbnail_url

Alias for field number 5

title

Alias for field number 0

url

Alias for field number 1

pskb_website.models.file.get_removed_file_listing_text(text, title)[source]

Remove given title from file listing text and return result

Parameters:text – Text of file listing file
Returns:String of text with title removed
pskb_website.models.file.get_updated_file_listing_text(text, article_url, title, author_url, author_name, author_img_url=None, thumbnail_url=None, stacks=None)[source]

Update text for new article listing

Parameters:
  • text – Text of file listing file
  • article_url – URL to article
  • title – Title of article to put in listing
  • author_url – URL to author
  • author_name – Name of author (i.e. login/username)
  • author_img_url – Optional URL to image for author
  • thumbnail_url – Optional URL to thumbnail image for article
  • stacks – Optional list of stacks article belongs to
Returns:

String of text with article information updated

pskb_website.models.file.in_review_article_path()[source]

Get path to in-review article file listing

Returns:Path to in-review article file listing file
pskb_website.models.file.in_review_articles(branch=u'master')[source]

Get iterator through list of in-review articles from file listing

Parameters:branch – Name of branch to save file listing to
Returns:Generator to iterate through file_listing_item tuples
pskb_website.models.file.published_article_path()[source]

Get path to published article file listing

Returns:Path to published article file listing file
pskb_website.models.file.published_articles(branch=u'master')[source]

Get iterator through list of published articles from file listing

Parameters:branch – Name of branch to save file listing to
Returns:Generator to iterate through file_listing_item tuples
pskb_website.models.file.read_file(path, rendered_text=True, branch=u'master', use_cache=True, timeout=480)[source]

Read file contents

Parameters:
  • path – Short path to file, not including repo or owner
  • rendered_text – Read rendered markdown text (True) or raw text (False)
  • branch – Name of branch to read file from
  • use_cache – Boolean to read from cache if available and save if not found in cache (use False to bypass any cache interaction, useful for very large files)
  • timeout – Cache timeout to save contents with (in seconds) - only used if use_cache is True
Returns:

Text of file or None if file could not be read

pskb_website.models.file.read_file_details(path, rendered_text=True, branch=u'master')[source]

Read file details including SHA and contents

Parameters:
  • path – Short path to file, not including repo or owner
  • rendered_text – Read rendered markdown text (True) or raw text (False)
  • branch – Name of branch to read file from
Returns:

remote.file_details tuple or None if file is missing

pskb_website.models.file.read_items_from_file_listing(text)[source]

Generator to yield parsed file_listing_item from text

Parameters:text – Raw text as read from file listing file
Returns:Generator to iterate through file_listing_item tuples
pskb_website.models.file.read_redirects(branch=u'master')[source]

Read redirects file and parse into a dictionary mapping an old url to a new url

Parameters:branch – Branch to read redirect file from
Returns:Dictionary with keys for old url and values for new url

The format of the redirect file is two URLs per line with whitespace between them:

http://www.xyz.com http://www.xyz.com/1
http://www.xyz.com/2 http://www.xyz.com/3

This means redirect http://www.xyz.com to http://www.xyz.com/1 and redirect http://www.xyz.com/2 to http://www.xyz.com/3.

Each line can start with an optional ‘- ‘, which will be ignored.

Any lines starting with a ‘#’ or not containing two tokens is ignored.

pskb_website.models.file.remove_article_from_listing(title, status, committer_name, committer_email, branch=u'master')[source]

Remove article title from file listing

Parameters:
  • title – Title of article to remove from listing
  • status – PUBLISHED, IN_REVIEW, or DRAFT
  • committer_name – Name of user committing change
  • committer_email – Email of user committing change
  • branch – Name of branch to save file listing to
Returns:

True or False if file listing was updated

pskb_website.models.file.sync_file_listing(all_articles, status, committer_name, committer_email, branch=u'master')[source]

Synchronize file listing file with contents of repo

Parameters:
  • all_articles – Iterable of article objects that should be synced to listing
  • status – PUBLISHED, IN_REVIEW, or DRAFT
  • committer_name – Name of user committing change
  • committer_email – Email of user committing change
  • branch – Name of branch to save file listing to
Returns:

Boolean to indicate if syncing succeeded or failed

This can be a very expensive operation because it heavily calls the remote API so be careful calling this for API limits and performance. Ideally this should at least be run as some kind of background process.

pskb_website.models.file.update_article_listing(article_url, title, author_url, author_name, committer_name, committer_email, author_img_url=None, thumbnail_url=None, stacks=None, branch=u'master', status=u'draft')[source]

Update article file listing with given article info

Parameters:
  • article_url – URL to article
  • title – Title of article to put in listing
  • author_url – URL to author
  • author_name – Name of author (i.e. login/username)
  • committer_name – Name of user committing change
  • committer_email – Email of user committing change
  • author_img_url – Optional URL to author’s image
  • thumbnail_url – Optional URL to thumbnail image for article
  • stacks – Optional list of stacks article belongs to
  • branch – Name of branch to save file listing to
  • status – PUBLISHED, IN_REVIEW, or DRAFT to add article to file listing. All other file listings will also be updated to remove this article if it exists there.
Returns:

True or False if file listing was updated

Heart

Module to manage CRUD operations on ‘heart’ing guides

Image

Save and read image files to/from github

pskb_website.models.image.github_url_from_upload_path(path, name, branch='master')[source]

Get URL to see raw image on github from the path the file was uploaded to

Parameters:
  • path – Path Full path file was save to github with
  • name – Name file was saved with
  • branch – Branch image was saved to
Returns:

URL to see content on github

pskb_website.models.image.main_image_path()[source]

Get path to main repos images

pskb_website.models.image.save_image(file_, extension, message, name, email, branch='master')[source]

Save image to github as a commit

Parameters:
  • file – Open file object containing image
  • message – Commit message to save image with
  • name – Name of user committing image
  • email – Email address of user committing image
  • branch – Branch to save image to
Param:

Extension to use for saved filename

Returns:

Public URL to image or None if not successfully saved

Lib

Collection of shared functionality for models subpackage

pskb_website.models.lib.contribution_stats()[source]

Get total and weekly contribution stats for default repository

Returns:Ordered dictionary keyed by author login name and ordered by most commits this week Each value in dictionary is a dictionary of stats for that contributor
pskb_website.models.lib.contributors_to_ignore()[source]

Get set of logins to ignore from all contribution stats

Returns:Set of logins
pskb_website.models.lib.to_json(object_, exclude_attrs=None)[source]

Return json representation of object

Parameters:exclude_attrs – List of attributes to exclude from serialization
Returns:json representation of object as a string