diff --git a/README.md b/README.md index c4ded76..5927087 100644 --- a/README.md +++ b/README.md @@ -1 +1,40 @@ -# webqueue2-api \ No newline at end of file +# webqueue2 API +A Python based parser and RESTful API for ECN's webqueue. + +## Usage +### Install via pip: +``` +pip install git+https://github.itap.purdue.edu/ECN/webqueue2-api@#egg=webqueue2-api +``` +For example, to install version 0.9.1: +``` +pip install git+https://github.itap.purdue.edu/ECN/webqueue2-api@0.9.1#egg=webqueue2-api +``` + +### Install via requirements file: +``` +git+https://github.itap.purdue.edu/ECN/webqueue2-api@#egg=webqueue2-api +``` +For example, to install version 0.9.1: +``` +git+https://github.itap.purdue.edu/ECN/webqueue2-api@0.9.1#egg=webqueue2-api +``` + +## Contributing +1. Clone the git repo: +```bash +git clone https://github.itap.purdue.edu/ECN/webqueue2-api.git +``` +2. Create and activate Python virtual environment: +```bash +python3 -m venv venv +source venv/bin/activate +``` +3. Install dependencies: +```bash +# Older versions of pip may fail to install newer packages. +pip install -U pip +# Install the webqueue2-api package in editable mode with all extra packages. +pip install -e .[all] +``` +4. Make changes and create a PR. \ No newline at end of file diff --git a/__init__.py b/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/docs/Dev Environment Setup Guide.md b/docs/Dev Environment Setup Guide.md new file mode 100644 index 0000000..43d36b8 --- /dev/null +++ b/docs/Dev Environment Setup Guide.md @@ -0,0 +1,274 @@ +# Dev Environment Setup Guide +This document will walk you through the setup and configuration of a development environment for webqueue2 using the provided development machines, SSH authentication, GitHub and VS Code. + +## Prerequisites + +### On Your Computer +- [VS Code](https://code.visualstudio.com/download) +- [Cisco AnyConnect for WebVPN](https://webvpn.purdue.edu/) + +### On The Development Computer + +!!! Note + These are already installed on the provided development machines. + +- [git](https://git-scm.com/downloads) +- [NodeJS](https://nodejs.org/en/) >= v14.11.0 +- npm >= v6.14.8 +- npx >= v6.14.8 +- [Python](https://www.python.org/downloads/) == 3.6.9 + +## Configuring Your SSH Keys +We will be using SSH keys to authenticate to both the development machines and GitHub. + +In either PowerShell on Windows or bash on macOS/Linux, run the following command and accept all defaults by pressing Enter: +```none +ssh-keygen +``` +This will create the files `id_rsa` and `id_rsa.pub` in the `.ssh` folder inside your user's folder. Your user's folder can usually be found at: + +=== "Windows" + ```none + C:\Users\ + ``` +=== "macOS" + ```none + /Users/ + ``` +=== "Linux" + ```none + /home/ + ``` + +Most CLI shells like PowerShell and bash use the ~ (tilda) key as a shortcut for your user's folder. + +You can confirm these files were created by running: +```none +ls ~/.ssh/ +``` + +## Configuring SSH +In your editor of choice, create the file `~/.ssh/config` and add this: + +!!! tip + Replace `campb303` with your career account username and replace `w2vm1` with the name of the provided development machine you're connecting to. + +```none +Host campb303-w2vm1 + HostName w2vm1.ecn.purdue.edu + User campb303 + # Forward webqueue2 Frontend Port + LocalForward 3000 localhost:3000 + # Forward webqueue2 API Port + LocalForward 5000 localhost:5000 + # Forward webqueue2 Docs Port + LocalForward 6060 localhost:6060 +``` + +The configuration above will allow you to connect to the development machine and automatically forward ports for development tools to work. Here's a bit more detail about what's going on: + +| Key | Value | +|--------------|----------------------------------------------------------------------------------| +| Host | A friendly name to identify an SSH host by. This can be anything. | +| HostName | The DNS name or IP address of the computer you're connecting to. | +| User | The name of your user on the computer you're connecting to. | +| LocalForward | Forwards a port on your computer to a port on the computer you're connecting to. | + +!!! tip + You need to be connected to WebVPN before SSH'ing into a the development machine. + +To test your configuration, run `ssh` followed by the `Host` value. When prompted for your password, enter your career account password and press Enter. + +!!! warning + Most shell environemnts like PowerShell and bash do not show your password being typed but it is being typed. + +For the configuration above you would run: + +```none +ssh campb303-w2vm1 +campb303@w2vm1's password: +``` + +## Adding SSH Keys +Now that we've generated SSH keys and configured our host entries, we need to add our SSH key to the host. This will allow us to connect to these machines without passwords later. + +!!! tip + Replace `HOST` below with the value from above. _Example:_ `campb303-w2vm1` + +=== "PowerShell on Windows" + ```powershell + type $env:USERPROFILE\.ssh\id_rsa.pub | ssh HOST "cat >> .ssh/authorized_keys" + ``` +=== "bash on macOS/Linux" + ```bash + ssh-copy-id HOST + ``` + +If the key was added successfully, you can login without entering a password by running: +``` +ssh HOST +``` + +## Installing VS Code +Download and install [VS Code](https://code.visualstudio.com/download). Be sure to add `code` to your PATH. + +=== "Windows" + + Adding `code` to your PATH on Windows is a checkbox in the installer: + + ![VS Code Install Options on Windows](https://i0.wp.com/www.techomoro.com/wp-content/uploads/2019/06/5.jpg?w=596&ssl=1) + + _Image from [this article on Techomoro](https://www.techomoro.com/installing-visual-studio-code-on-windows-10/)_ + +=== "macOS/Linux" + + Adding `code` to your PATH on macOS/Linux is accessible by searching for "PATH" in the Command Pallete. You can access the Command Pallete with the keyboard shortcut Command/Ctrl + Shift + P: + + ![VS Code Install Options on macOS/Linux](https://i.stack.imgur.com/Ng886.png) + + _Image from [this StackOverflow thread](https://stackoverflow.com/questions/30065227/run-open-vscode-from-mac-terminal)_ + +## Connecting To The Development Machine +Install the [Remote - SSH](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) plugin. After installation a new icon will appear in the sidebar: + +![Remote SSH Plugin Icon](images/Dev%20Environment%20Setup%20Guide/Remote%20SSH%20Icon.png) + +- Click on the Remote SSH icon and you'll see the SSH host you just defined +- Select the host and click the New Window icon to connect. A new window connected to that host will appear + +!!! note + This may take a couple of minutes on the first connection while VS Code installs its server. + +![Remote SSH Connection Example](images/Dev%20Environment%20Setup%20Guide/Connect%20to%20Remote%20SSH%20Host.gif) + +If prompted for a platform, select Linux: +![VS Code Select Platform](images/Dev%20Environment%20Setup%20Guide/VS%20Code%20Select%20Platform.png) + +## Adding Your SSH Keys to GitHub +Because the development machine will be the computer that connects to GitHub, we need to create another SSH key and add it to our GitHub profile: + +First, open VS Code's integrated terminal by pressing Control + ~ (tilda) + +![Open VS Code's integrated terminal](images/Dev%20Environment Setup%20Guide/Open%20VS%20Code%20Integrated%20Terminal.gif) + +Now run the following command and accept all defaults by pressing Enter: +```bash +ssh-keygen +``` + +This will create the files `id_rsa` and `id_rsa.pub` in `~/.ssh/`. You can confirm this by running: +```bash +ls ~/.ssh/ +``` + +Now copy the public key from `id_rsa.pub` by openning the file in VS Code, selecting its contents and copying it. You can open the file in VS Code by running the following in the integrated terminal: + +!!! danger + Do not copy your private key from `id_rsa`! This key should never leave your machine. + +```bash +code ~/.ssh/id_rsa.pub +``` + +Now go to [github.itap.purdue.edu/settings/keys](https://github.itap.purdue.edu/settings/keys). You may be prompted to login using your career account username and password. + +- Click the "New SSH Key" button +- Give the key a title that tells you what device the key is from (e.g. Desktop or Dev Machine) +- Paste the contents of `id_rsa.pub` into the key box +- Click the "Add SSH Key" button + +![Add SSH Key to GitHub](images/Dev%20Environment%20Setup%20Guide/Add%20SSH%20Key%20to%20GitHub.gif) + +## Cloning and Opening the Repository +Using the integrated terminal in VS Code, run: +```none +git clone git@github.itap.purdue.edu:ECN/webqueue2.git +``` +This will create a `webqueue2` folder in your user's home directory. Open this directory using the "Open Folder" button: + +![Open Repo](images/Dev%20Environment%20Setup%20Guide/Open%20Repo.gif) + +!!! note + VS Code will automatically reconnect to the last remote host used when it reopens. + +!!! tip + If you need to reconnect manually, there will now be an option to open the webqueue2 folder directly from the Remote Hosts menu: + + ![Remote Folder Open](images/Dev%20Environment%20Setup%20Guide/Remote%20Folder%20Open.png) + +## Configuring VS Code + +### Installing Extensions +There are three groups of plugins to install depending on what kind of development you're doing: + +#### General plugins, (needed by everyone): + +- [Python](https://marketplace.visualstudio.com/items?itemName=ms-python.python) for working with Python virtual environments and debugging +- [Git Graph](https://marketplace.visualstudio.com/items?itemName=mhutchie.git-graph) for a more detailed view of git info +- [Markdown Preview GitHub Styling](https://marketplace.visualstudio.com/items?itemName=bierner.markdown-preview-github-styles) for previewing Markdown as it will appear on GitHub + +#### Frontend Extensions: +- [ES Lint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) for JavaScript linting +- [Babel JavaScript](https://marketplace.visualstudio.com/items?itemName=mgmcdermott.vscode-language-babel) for JavaScript and JSX syntax highlighting and error checking +- [MDX](https://marketplace.visualstudio.com/items?itemName=silvenon.mdx) to provide MDX syntax support + +#### Backend/API Extensions: +- [Python Docstring Generator](https://marketplace.visualstudio.com/items?itemName=njpwerner.autodocstring) for generating Google style docstrings according to section 3.8 of [Google's Python style guide](https://google.github.io/styleguide/pyguide.html#s3.8-comments-and-docstrings) + +### Configuring Extensions + +#### Python +The Python extension supports virtual environments but needs to be told where the virtual environment is. + +Create or modify the file `.vscode/settings.json` and add the following: +```none +"python.pythonPath": "./api/venv/bin/python3" +``` + +!!! tip + The Python extension may complain and tell you to select another interpreter. Ignore this warning for now. + +#### Python Docstring Generator +For consistentcy, we'll use a docstring template. Create or modify the file `.vscode/settings.json` and add the following: +```none +"autoDocstring.customTemplatePath": "./docstring-format.mustache" +``` + +At this point, your `.vscode/settings.json` file should look like this: +```none +{ + "python.pythonPath": "./api/venv/bin/python3", + "autoDocstring.customTemplatePath": "./docstring-format.mustache" +} +``` + +## Configuring Tools +Install npm dependencies: +```bash +npm install +``` + +Create the Python virtual environment: +```bash +npm run venv:create +``` + +## Using Tools +All of the tools in this project are accessible as an npm task so you can interact with them by running `npm run `. The tasks are: + +| Task | Description | +| - | - | +| `frontend:start` | This will start a development server on [localhost:3000](http://localhost:3000). (If the server is on your local machine, this will also launch your default browser at that address.) As you save changes in the `public/` or `src/` directories you'll see your changes in the browser. (API requests are automatically proxied to the API server.) | +| `frontend:start:docs` | This will start a local server on [localhost:6060](http://localhost:6060) showing you the React component documentation. As you change a components documentation file in `/src/components//.md` you'll see your changes in the browser. +| `frontend:build` | This will output a static bundle of the frontend in `build/` that can be put on any webserver. | +| `frontend:build:docs` | This will output a static bundle of the frontend documentation in `styleguidist/frontend-docs` that can be put on any webserver. | +| `frontend:kill` | Kills the runaway frontend process(es). | +| `frontend:kill:docs` | Kills the runaway frontend docs process(es). | +| `api:start` | This will start a local WSGI server on [localhost:5000](http://localhost:5000) to access the API. You can interact with the API using `curl` or [Postman](https://www.postman.com/) | +| `api:start:docs` | This will start a local server on [localhost:8000](http://localhost:8000) to access the API docs. As you change API documentation files in `api/documentation/docs` you'll see your changes in the browser. | +| `api:build:docs` | This will output a static bundle of the API documentation in `api/documentation/site` that can be put on any webserver. | +| `api:kill` | Kills the runaway API process(es). | +| `api:kill:docs` | Kills the runaway API docs process(es). | +| `venv:create` | This will create a virtual environment in `api/venv` and install requirements from `api/requirements.txt`. | +| `venv:delete` | This will delete the folder `api/venv`. | +| `venv:reset` | This will run `venv:delete` then `venv:create`. | \ No newline at end of file diff --git a/docs/Material for mkdocs Formatting.md b/docs/Material for mkdocs Formatting.md new file mode 100644 index 0000000..3edd513 --- /dev/null +++ b/docs/Material for mkdocs Formatting.md @@ -0,0 +1,105 @@ +# Material for mkdocs Formatting + +## Admonitions +See: [Material for mkdocs: Admonitions](https://squidfunk.github.io/mkdocs-material/reference/admonitions/#admonitions) + +!!! note + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod + nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor + massa, nec semper lorem quam in massa. + +??? summary + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod + nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor + massa, nec semper lorem quam in massa. + +???+ info + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod + nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor + massa, nec semper lorem quam in massa. + +!!! success "Custom Title" + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod + nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor + massa, nec semper lorem quam in massa. + + +## Code Blocks +See: [Material for mkdocs: Code Blocks](https://squidfunk.github.io/mkdocs-material/reference/code-blocks/#highlight) + +``` python +# This is a Python code block. +print("Hello world!") if __name__ == "__main__" +``` +``` js linenums="1" +# This is a JavaScript code block with line numbers. +( _ => console.log("Hello world!"))(); +``` +``` md hl_lines="3" +# This is a Markdown code block with line highlights and nested code block. + ``` js + ( _ => console.log("Hello world!"))(); + ``` +``` + +This is an inline Java highlight `#!java system.out.println("Hello world!")` + + +## Content Tabs + +See: [Material for mkdocs: Content Tabs](https://squidfunk.github.io/mkdocs-material/reference/content-tabs/#content-tabs) + +### Basic Tabs +```md +=== "Tab 1" + Hello +=== "Tab 2" + World +``` + +=== "Tab 1" + Hello +=== "Tab 2" + World + +### Tabs in Admonitions with Code Blocks +```md +!!! example + "Hello world" in many languages: + === "Python" + ```python + print("Hello world!") if __name__ == "__main__" + ``` + === "JavaScript" + ```js + ( _ => console.log("Hello world!"))(); + ``` +``` + +!!! example + "Hello world" in many languages: + === "Python" + ```python + print("Hello world!") if __name__ == "__main__" + ``` + === "JavaScript" + ```js + ( _ => console.log("Hello world!"))(); + ``` + +## Data Tables +See: [Material for mkdocs: Data Tables](https://squidfunk.github.io/mkdocs-material/reference/data-tables/#data-tables) + +``` +| Method | Description | +| ----------- | ------------------------------------ | +| `GET` | :material-check: Fetch resource | +| `PUT` | :material-check-all: Update resource | +| `DELETE` | :material-close: Delete resource | +``` + +| Method | Description | +| ----------- | ------------------------------------ | +| `GET` | :material-check: Fetch resource | +| `PUT` | :material-check-all: Update resource | +| `DELETE` | :material-close: Delete resource | \ No newline at end of file diff --git a/docs/api/API Overview.md b/docs/api/API Overview.md new file mode 100644 index 0000000..6384e0d --- /dev/null +++ b/docs/api/API Overview.md @@ -0,0 +1,177 @@ +# *(draft)* API Overview +Using Flask, Flask Restful and Flask JWT (correct?) The api works as a direct connection to the storage for the items stored by the Qcli, allowing front end calls to request parsed information via url. + +Endpoints | Use +:---: | :--- +[**/api/login**](#login) | Receives a JSON encoded username and password. Sets a Refresh token cookie and returns an access token. +[**/api/tokens/refresh**](#tokensrefresh) | Gets a new refresh token. +[**/api/data/<string:queue>/<int:number>**](#acessing-items) | Returns a JSON encoded Item. +[**/api/data/<string:queues>**](#accessing-queues) | Returns a JSON encoded Queue. +[**/api/data/get_queues**](#accessing-queue-counts) | Returns a list of queues and their item counts. + +## login + +#### **Description** +Acts as a way to authenticate users to access data parsed in the back end. + +#### **Arguments** +The api login accpets a username and an already hashed password. +```json +{ + "username": form.username, + "password": sha256(form.password) +} +``` +The api accepts the hashed password and salts and hashes it an additional time and attempts to authenticate the username and the password using *insert part of flask being used here*. + +#### **Returns** +After sucesfully authenticating the username and password, the api will return an access token to then be stored in a browser cookie on the frontend +```json +{ "access_token": access_token } +``` + +#### **Errors** + +| Error | Reason | +| ---- | ---- | +| **422** | Returns if data is not json or if the json data is not formatted correctly | +| **401** | Returns if the username and/or password is invalid | + +## tokens/refresh + +#### **Description** + +Acts as a revalidation of an already authenticated user and supplies a newly created access token. + +## Acessing Items + +#### **Description** + +Items are individual "tickets", stored in a collective queue with other items. Item numbers are unique only within each queue, meaning that to access a specific item, its queue name must also be known in addition to it's item number. `ce100`, `me23`, and `eee48` would all be specific items that can all be accessed. + +#### **Arguments** + +**/api/data/*<string:queue>*/*<int:number>*** + +Argument | Type | Description +:---- | :----: | :---- +`queue` | String | The queue an item is located in +`item` | Int | The item's distinct number within the specified queue +`headersOnly` *(Optional)* | Boolean | Specify weather to only returns the headers of an item or the whole item + +An item can be accessed directly from the url by passing the queue name and the item number. +By default, the entire contents of an item are returned, but the headers of an item, without any of the content within that item, can also be returned by passing the `headersOnly=True` argument within the url: + +`/api/data/ce/100` will default to `headersOnly=False` and return the entirety of `ce 100` + +`/api/data/ce/100?headersOnly=True` will return only the headers of `ce 100` + +#### **Returns** + +When `headersOnly=False`, the full contents of an item will be returned in a json structure with these keys: + +Key | Value +------|------ +`lastUpdated` | An ISO 8601 formatted time string showing the last time the file was updated. +`headers` | A list of dictionaries containing header keys and values. +`content` | A list of section dictionaries. +`isLocked` | A boolean showing whether or not a lockfile for the item is present. +`userEmail` | The email address of the person who this item is from. +`userName` | The real name of the person who this item is from. +`userAlias` | The Purdue career account alias of the person this item is from. +`assignedTo` | The Purdue career account alias of the person this item is assigned to +`subject` | The subject of the original message for this item. +`status` | The most recent status update for the item. +`priority` | The most recent priority for this item. +`department` | The most recent department for this item. +`dateReceived` | The date this item was created. +`jsonData` | A JSON serializable representation of the Item. + +If `headersOnly=True`, then all of the key/value pairs are returned except for the `content` key and the list of dictionaries associated with it. + +## Accessing Queues + +#### **Description** + +Additionally, the information relating to all items in a queue can be accesed by simply naming the queue in the URL. Unlike acessing a specific item, acessing a queue only returns the header information for each item to decrease the time it takes to parse the information from the stored items. + +#### **Arguments** + +Accessing a queue is similar to accessing an individual item except that multiple item dictionaries are returned within a list as opposed to just one item in a singular dictionary. + +**/api/data/*<string:queues>*** + +| Argument | Type | Description | +| ---- | :----: | :---- | +| `queue` | String | The name of a queue | +| `headersOnly` *(Optional)* | Boolean | Specify weather to only returns the headers of an item or the whole item | + +By default, acessing an entire queue will return only the header information for the items within a given queue, however, it is possible to return the entire contents of all the items within a queue by passing `headersOnly=False` within the url: + +| URL | Return Description | +| --- | --- | +| `/api/data/me` | Defaults to `headersOnly=True` and returns a list of all items in the `me` queue with only the header information included. | +| `/api/data/ce?headersOnly=False` | Returns a list of all the items in the `me` queue with the entire contents of every item included. | + +It is also possible to return multiple queues by passing more than one queue name in the url. separating each queue name with "+": + +| URL | Return Description | +| --- | --- | +| `/api/data/eee+cnit` | Defaults to `headersOnly=True` and returns a list of all the items in both the `eee` and `cnit` queues with only the header information included. | +| `/api/data/eee+cnit?headersOnly=False` | Returns a list of all the items in both the `eee` and `cnit` queues with the entire contents of every item from both queues included. | + +#### **Returns** + +Returns a list of queues, with each queue being it's own dictionary with a list of items, each item represented by a dictionary. + +**JSON output:** +```json +[ + {'name': 'queue_name', + 'items': ['list_of_item_dictionaries] + }, + + {'name': 'queue_name', + 'items': ['list_of_item_dictionaries] + } +] +``` +## Accessing Queue Counts + +#### **Description** + +This will return a dictionary of all valid queues with the number of items within each queue. + +#### **Arguments** + +This function doesn't require any arguments from the url. + +#### **Returns** + +Returns a list of dictionaries with these key value pairs: +**/api/data/get_queues** + +| Key | Type | Value | +| --- | ---- | ----- | +| `name` | string | the name of the queue | +| `number_of_items` | int | the number of items within the queue | + +**JSON output:** +```json +[ + { + 'name': 'bidc', + 'number_of_items': 5 + }, + + { + 'name': 'epics', + 'number_of_items': 6 + }, + + { + 'name': 'wang', + 'number_of_items': 13 + } +] +``` \ No newline at end of file diff --git a/docs/api/Authentication.md b/docs/api/Authentication.md new file mode 100644 index 0000000..1cedd3e --- /dev/null +++ b/docs/api/Authentication.md @@ -0,0 +1,76 @@ +# Authentication + +The webqueue2 API uses a two stage authentication system combining Active Directory and [HTTP Token](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication) (or "bearer") authentication. + +All API calls require an access token. You can get an access token by making a POST request to the `/api/login` endpoint containing the JSON encoded username and password of a valid user. + +??? info "Who is a valid user?" + A valid user is a non-admin BoilerAD user who is in the `00000227-ECN-webqueue` group. Users cannot be added directly to this group. To be included in this group, a user must exist in one of the following groups: + + - `00000227-ECNStaff` + - `00000227-ECNStuds` + - `00000227-ECN-webqueue-misc` + +=== "fetch" + ```javascript + const accessToken = (async _ => { + const loginInit = { + method: "POST", + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({ "username": USERNAME, "password": PASSWORD}) + }; + + let loginResponse = await fetch("API_URL/api/login", loginInit); + let data = await loginResponse.json(); + + if (data === null){ + return false; + } + + if (!loginResponse.ok){ + console.error(`Login failed. Got code ${loginResponse.status} (${loginResponse.statusText})`); + return false; + } + + return data.access_token || false; + })(); + ``` + +=== "cURL" + !!! warning + It is **strongly** recomended to store and retrieve your login credentials in a [cURL config file](https://everything.curl.dev/cmdline/configfile) that only your user can read to avoid exposing your credentials to your shell history or the host process table. + + Create a cURL config file named `wq2_login.config`: + ```bash + nano ~/wq_login.config + ``` + + Add the cURL options: + ```python + # ~/wq_login.config + request = POST + header = "Content-Type: application/json" + data = {"username":"USERNAME","password":"PASSWORD"} + url = "API_URL/api/login" + ``` + + Restrict read permissions to your user: + ```bash + chmod 700 ~/wq_login.config + ``` + + Run cURL using your new config file: + ```bash + curl -K ~/wq_login.config + ``` + ``` + # Expected Output: + {"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MTYxODI1MjMsIm5iZiI6MTYxNjE4MjUyMywianRpIjoiYzI2ZjY4NDctZGU2OC00ODUzLWI4ODctMTBmZDAyMDcyY2U0IiwiZXhwIjoxNjE2MTgzNDIzLCJzdWIiOiJjYW1wYjMwMyIsImZyZXNoIjpmYWxzZSwidHlwZSI6ImFjY2VzcyIsImNzcmYiOiJjYjYzZWE1My1jOWQ2LTQ5YTItYmZhMi0wY2U4N2Q3YzcxZDcifQ.T7bezsOMreMCXWR0R5w5BKI673hpOquCOnvT1XkyDjY"} + ``` + + ??? tip "Tip for Parsing Tokens in Bash" + You can parse the access token using Python like this: + ```bash + curl -K ~/wq_login.config | \ + python3 -c "import sys, json; print(json.load(sys.stdin)['access_token'])" + ``` \ No newline at end of file diff --git a/docs/api/Getting Started.md b/docs/api/Getting Started.md new file mode 100644 index 0000000..e6b5fea --- /dev/null +++ b/docs/api/Getting Started.md @@ -0,0 +1,27 @@ +# Getting Started + +The webqueue2 API is organized around [REST](https://en.wikipedia.org/wiki/Representational_state_transfer). The API has resource oriented URLs, accepts and returns JSON encoded request bodies, can be modified via the query string and uses standard HTTP response codes and verbs. + +## Basic Usage + +!!! example "Get the number of Items in a Queue" + === "fetch" + ```javascript + ()(); + ``` + + === "cURL" + ```bash + curl -K + ``` + +!!! example "Get the subject of an Item" + === "fetch" + ```javascript + console.log + ``` + + === "cURL" + ```bash + curl -K + ``` \ No newline at end of file diff --git a/docs/api/Installation.md b/docs/api/Installation.md new file mode 100644 index 0000000..6552a27 --- /dev/null +++ b/docs/api/Installation.md @@ -0,0 +1,57 @@ +# Installation + +The api is hosted as its own package in a dedicated git repository, https://github.itap.purdue.edu/ECN/webqueue2-api, and is easily installable via `pip`. + +### Install via command line +This is the syntax for installing the api: +``` +pip install git+https://github.itap.purdue.edu/ECN/webqueue2-api@#egg=webqueue2-api +``` +For example, to install version `0.9.1`, replace `` in the above command like this: +``` +pip install git+https://github.itap.purdue.edu/ECN/webqueue2-api@0.9.1#egg=webqueue2-api +``` + +### Install via requirements.txt +Append this line in the requirements file: +``` +git+https://github.itap.purdue.edu/ECN/webqueue2-api@#egg=webqueue2-api +``` +For example, to install version `0.9.1`, replace `` in the above line above like this: +``` +git+https://github.itap.purdue.edu/ECN/webqueue2-api@0.9.1#egg=webqueue2-api +``` +### Package Structure +The name of the package itself is `webqueue2-api` and follows this structure: +``` +─webqueue2-api (git repo) +│ +├───__init__.py +├───api.py +├───ECNQueue.py +└───setup.py +``` +**ECNQueue.py:** +The parser that iterates through items and resturns a json formatted string. + +**api.py:** +The bridge between the fronted and the parser: the frontend sends requests to `api.py` which are translated into functions present in the `ECNQueue.py`, and the json returned by `ECNQueue.py` is thus returned to the frontend. + +**setup.py:** +Stores important information about the `webqueue2-api` package including: + +* The version +* Dependencies that are installed with `webqueue2-api` +* The name of the package (`webqueue2-api`) +* The python version requirement, which is anything including and beyond python version 3.6 + +**\_\_init\_\_.py** +Specifies to `pip` that the current directory is a package, doesn't contain any code, but any code contained within `__init__.py` is executed when ever the `webqueue2-api` package is imported. + +### Importing the package + +The package cannot be referenced directly (need to check on this), however, both the `api` and `ECNQueue` modules can be directly imported after successfully installing the webqueue2-api package: +```python +import ECNQueue +import api +``` \ No newline at end of file diff --git a/docs/api/Items.md b/docs/api/Items.md new file mode 100644 index 0000000..1eea0ec --- /dev/null +++ b/docs/api/Items.md @@ -0,0 +1 @@ +# Items diff --git a/docs/api/Queues.md b/docs/api/Queues.md new file mode 100644 index 0000000..c7b35ed --- /dev/null +++ b/docs/api/Queues.md @@ -0,0 +1 @@ +# Queues diff --git a/docs/api/awesome-pages.yaml b/docs/api/awesome-pages.yaml new file mode 100644 index 0000000..4bfc79f --- /dev/null +++ b/docs/api/awesome-pages.yaml @@ -0,0 +1,9 @@ +# YAML Configuration for Awesome Pages mkdocs Plugin +# See: https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin +nav: + - Getting Started.md + - Installation.md + - Authentication.md + - Items.md + - Queues.md + - ... \ No newline at end of file diff --git a/docs/awesome-pages.yaml b/docs/awesome-pages.yaml new file mode 100644 index 0000000..e502d65 --- /dev/null +++ b/docs/awesome-pages.yaml @@ -0,0 +1,4 @@ +# YAML Configuration for Awesome Pages mkdocs Plugin +# See: https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin +nav: + - ... \ No newline at end of file diff --git a/docs/css/custom_css.css b/docs/css/custom_css.css new file mode 100644 index 0000000..9147825 --- /dev/null +++ b/docs/css/custom_css.css @@ -0,0 +1,9 @@ +.md-typeset__table { + width: 100% !important; +} + +table { + width: 100% !important; + display: table !important; + border-spacing: 0px !important; +} diff --git a/docs/ecnqueue.md b/docs/ecnqueue.md new file mode 100644 index 0000000..9f329aa --- /dev/null +++ b/docs/ecnqueue.md @@ -0,0 +1,21 @@ +# ECNQueue documentation + +## Item Class + +::: webqueue2_api.ECNQueue.Item + :docstring: + +### Item functions + +::: webqueue2_api.ECNQueue.Item + :members: + +## Queue Class + +::: webqueue2_api.ECNQueue.Queue + :docstring: + +### Queue Functions + +::: webqueue2_api.ECNQueue.Queue + :memebers: diff --git a/docs/images/Dev Environment Setup Guide/Add SSH Key to GitHub.gif b/docs/images/Dev Environment Setup Guide/Add SSH Key to GitHub.gif new file mode 100644 index 0000000..b812c5b Binary files /dev/null and b/docs/images/Dev Environment Setup Guide/Add SSH Key to GitHub.gif differ diff --git a/docs/images/Dev Environment Setup Guide/Connect to Remote SSH Host.gif b/docs/images/Dev Environment Setup Guide/Connect to Remote SSH Host.gif new file mode 100644 index 0000000..3d644dd Binary files /dev/null and b/docs/images/Dev Environment Setup Guide/Connect to Remote SSH Host.gif differ diff --git a/docs/images/Dev Environment Setup Guide/Open Repo.gif b/docs/images/Dev Environment Setup Guide/Open Repo.gif new file mode 100644 index 0000000..08cd8e3 Binary files /dev/null and b/docs/images/Dev Environment Setup Guide/Open Repo.gif differ diff --git a/docs/images/Dev Environment Setup Guide/Open VS Code Integrated Terminal.gif b/docs/images/Dev Environment Setup Guide/Open VS Code Integrated Terminal.gif new file mode 100644 index 0000000..505b847 Binary files /dev/null and b/docs/images/Dev Environment Setup Guide/Open VS Code Integrated Terminal.gif differ diff --git a/docs/images/Dev Environment Setup Guide/Remote Folder Open.png b/docs/images/Dev Environment Setup Guide/Remote Folder Open.png new file mode 100644 index 0000000..6a53201 Binary files /dev/null and b/docs/images/Dev Environment Setup Guide/Remote Folder Open.png differ diff --git a/docs/images/Dev Environment Setup Guide/Remote SSH Icon.png b/docs/images/Dev Environment Setup Guide/Remote SSH Icon.png new file mode 100644 index 0000000..32f210c Binary files /dev/null and b/docs/images/Dev Environment Setup Guide/Remote SSH Icon.png differ diff --git a/docs/images/Dev Environment Setup Guide/VS Code Select Platform.png b/docs/images/Dev Environment Setup Guide/VS Code Select Platform.png new file mode 100644 index 0000000..f69c3ed Binary files /dev/null and b/docs/images/Dev Environment Setup Guide/VS Code Select Platform.png differ diff --git a/docs/images/favicon.ico b/docs/images/favicon.ico new file mode 100755 index 0000000..f444752 Binary files /dev/null and b/docs/images/favicon.ico differ diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..000ea34 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,17 @@ +# Welcome to MkDocs + +For full documentation visit [mkdocs.org](https://www.mkdocs.org). + +## Commands + +* `mkdocs new [dir-name]` - Create a new project. +* `mkdocs serve` - Start the live-reloading docs server. +* `mkdocs build` - Build the documentation site. +* `mkdocs -h` - Print help message and exit. + +## Project layout + + mkdocs.yml # The configuration file. + docs/ + index.md # The documentation homepage. + ... # Other markdown pages, images and other files. diff --git a/docs/javascript/tablesort.js b/docs/javascript/tablesort.js new file mode 100644 index 0000000..394f8cf --- /dev/null +++ b/docs/javascript/tablesort.js @@ -0,0 +1,11 @@ +/* + * Configure Tablesort for sortable tables + * See: https://squidfunk.github.io/mkdocs-material/reference/data-tables/#sortable-tables + */ + +app.document$.subscribe(function() { + var tables = document.querySelectorAll("article table") + tables.forEach(function(table) { + new Tablesort(table) + }) +}) diff --git a/docs/webqueue2 backend overview.md b/docs/webqueue2 backend overview.md new file mode 100644 index 0000000..2620d60 --- /dev/null +++ b/docs/webqueue2 backend overview.md @@ -0,0 +1,12 @@ +# *(draft)* Webqueue2 backend overview + +!!! note + *This document should be renamed to `index.md` to make it the default landing page. The current index.md file contains information for mkdocs that maybe useful later* + +## Overview +In order to function, the backend of Webqueue2 relies primarily on two scripts, the `ECNQueue.py` script, and the `api.py` script. These two scripts work in conjuction with eachother inorder to read, parse, and transfer item and queue information created by the `qcli` to the frontend. + +### ECNQueue.py +The `ECNQueue.py` script does all of the data and information parsing. + +Items are currently stored in plain text within text files and all updates to those items are documented directly into those textfiles via the `qcli`. The `ECNQueue.py` script parses these text files and stores all the information regarding the item into a custom `Item` object. \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..bc8596a --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,64 @@ +################################################################################ +# mkdocs Settings +# See: https://www.mkdocs.org/user-guide/configuration/ +################################################################################ + +site_name: webqueue2 API +repo_url: https://github.itap.purdue.edu/ECN/webqueue2 +plugins: + - search + # Awesome Pages Settings + # See: https://github.com/lukasgeiter/mkdocs-awesome-pages-plugin + - awesome-pages: + filename: awesome-pages.yaml +markdown_extensions: + - toc: + permalink: ⚓︎ + - admonition + - pymdownx.details + - pymdownx.superfences + - pymdownx.highlight + - pymdownx.inlinehilite + - pymdownx.tabbed + - pymdownx.emoji: + emoji_index: !!python/name:materialx.emoji.twemoji + emoji_generator: !!python/name:materialx.emoji.to_svg + - mkautodoc + + + +################################################################################ +# Material for mkdocs Settings +# See: https://squidfunk.github.io/mkdocs-material/setup/changing-the-colors/ +################################################################################ + +# TODO: Implement versioning +# See: https://squidfunk.github.io/mkdocs-material/setup/setting-up-versioning/#versioning + +theme: + name: material + palette: + # Used to toggle dark mode. + # scheme: slate + primary: deep purple + accent: teal + icon: + logo: material/book-open + favicon: images/favicon.ico + features: + - navigation.sections + +extra: + social: + - icon: fontawesome/brands/slack + link: https://purdueecn.slack.com/archives/C019K7PSPNW + name: webqueue2 on Slack + - icon: fontawesome/brands/github + link: https://github.itap.purdue.edu/ECN/webqueue2 + name: webqueue2 on GitHub + +extra_javascript: + - https://cdnjs.cloudflare.com/ajax/libs/tablesort/5.2.1/tablesort.min.js + - javascript/tablesort.js +extra_css: + - css/custom_css.css \ No newline at end of file diff --git a/setup.py b/setup.py index bc5fc39..abb6552 100644 --- a/setup.py +++ b/setup.py @@ -1,46 +1,33 @@ -import setuptools, logging -from pathlib import Path - -# Configure the logger -logger_name = "webqueueapi_install_log" -logger = logging.getLogger(logger_name) -logger.setLevel(logging.DEBUG) - -# See Formatting Details: https://docs.python.org/3/library/logging.html#logrecord-attributes -# Example: Jan 28 2021 12:19:28 venv-manager : [INFO] Message -log_message_format = "%(asctime)s %(name)s : [%(levelname)s] %(message)s" -# See Time Formatting Details: https://docs.python.org/3.6/library/time.html#time.strftime -# Example: Jan 28 2021 12:19:28 -log_time_format = "%b %d %Y %H:%M:%S" -log_formatter = logging.Formatter(log_message_format, log_time_format) - -# Configure output to stdout -stream_handler = logging.StreamHandler() -stream_handler.setFormatter(log_formatter) -stream_handler.setLevel(logging.INFO) -logger.addHandler(stream_handler) - -# Configure out to logfile, located in '/tmp/webqueueapi install log.log' -log_file_path = Path(f"/tmp/{logger_name}.log") -file_handler = logging.FileHandler(log_file_path) -file_handler.setFormatter(log_formatter) -logger.addHandler(file_handler) - -logger.debug("Attempting to install webqueue2-api package") - -setuptools.setup( - name="webqueue2-api", +from setuptools import setup, find_packages + +# Define Dependencies for Extra Requires +conditional_dependencies = { + "dev":[ + "pylint" + ], + "docs": [ + "mkdocs", + "mkdocs-material", + "mkautodoc", + "mkdocs-awesome-pages-plugin" + ], +} + +def get_all_dependencies(): + """Returns a single array of all dependencies.""" + dependencies = [] + for condition in conditional_dependencies.keys(): + dependencies += conditional_dependencies[condition] + return dependencies + +setup( + name="webqueue2_api", version="0.9.1", description="A library for managing Purdue ECN's queue system.", - py_modules=['api', 'ECNQueue'], python_requires='>=3.6', + packages=find_packages(), install_requires = [ - # General Utilities - "pipdeptree", "gunicorn", - "pylint", - - # API "python-dotenv", "Flask-RESTful", "python-dateutil", @@ -49,12 +36,11 @@ "PyJWT == 1.*", # Custom version of python-ldap without SASL requirements "python-ldap @ git+https://github.itap.purdue.edu/ECN/python-ldap/@python-ldap-3.3.1", - - # API Documentation - "mkdocs", - "mkdocs-material", - "mkautodoc" - ] -) - -logger.info("webqueue2-api package installed sucessfully") \ No newline at end of file + "easyad", + ], + extras_require={ + "dev": conditional_dependencies["dev"], + "docs": conditional_dependencies["docs"], + "all": get_all_dependencies() + } +) \ No newline at end of file diff --git a/ECNQueue.py b/webqueue2_api/ECNQueue.py similarity index 100% rename from ECNQueue.py rename to webqueue2_api/ECNQueue.py diff --git a/webqueue2_api/__init__.py b/webqueue2_api/__init__.py new file mode 100644 index 0000000..3bec1e8 --- /dev/null +++ b/webqueue2_api/__init__.py @@ -0,0 +1 @@ +from . import api, ECNQueue \ No newline at end of file diff --git a/api.py b/webqueue2_api/api.py similarity index 98% rename from api.py rename to webqueue2_api/api.py index 73128f6..7fcefa4 100644 --- a/api.py +++ b/webqueue2_api/api.py @@ -10,7 +10,7 @@ from ldap.filter import escape_filter_chars # pylint says this is an error but it works so ¯\_(ツ)_/¯ from ldap import INVALID_CREDENTIALS as LDAP_INVALID_CREDENTIALS -import ECNQueue +from . import ECNQueue # Load envrionment variables for ./.env dotenv.load_dotenv() @@ -65,6 +65,10 @@ def user_is_valid(username: str, password: str) -> bool: if (username == "" or password == ""): return False + # Check for adm account + if username.endswith("adm"): + return False; + # Initialize EasyAD config = { "AD_SERVER": "boilerad.purdue.edu",