From 0fee14767d93314e3ad7f256019ca6fcab092418 Mon Sep 17 00:00:00 2001 From: KicaRonaldOkello <40671517+KicaRonaldOkello@users.noreply.github.com> Date: Thu, 20 Dec 2018 00:26:15 +0300 Subject: [PATCH] feat(Articles):Users can report articles This commit delivers a feature for user to report articles that violate terms of service [Delivers #162163282] --- .DS_Store | Bin 10244 -> 10244 bytes .gitignore | 1 + ATHENA/bin/activate | 78 +++++++ ATHENA/bin/activate.csh | 42 ++++ ATHENA/bin/activate.fish | 76 +++++++ ATHENA/bin/activate.ps1 | 150 ++++++++++++++ ATHENA/bin/activate_this.py | 36 ++++ ATHENA/bin/autopep8 | 11 + ATHENA/bin/chardetect | 11 + ATHENA/bin/coverage | 11 + ATHENA/bin/coverage-3.7 | 11 + ATHENA/bin/coverage3 | 11 + ATHENA/bin/coveralls | 11 + ATHENA/bin/django-admin | 11 + ATHENA/bin/django-admin.py | 5 + ATHENA/bin/dotenv | 11 + ATHENA/bin/easy_install | 11 + ATHENA/bin/easy_install-3.7 | 11 + ATHENA/bin/epylint | 11 + ATHENA/bin/futurize | 11 + ATHENA/bin/gunicorn | 11 + ATHENA/bin/gunicorn_paster | 11 + ATHENA/bin/isort | 11 + ATHENA/bin/markdown2 | 18 ++ ATHENA/bin/pasteurize | 11 + ATHENA/bin/pep8 | 11 + ATHENA/bin/pip | 11 + ATHENA/bin/pip3 | 11 + ATHENA/bin/pip3.7 | 11 + ATHENA/bin/py.test | 11 + ATHENA/bin/pycodestyle | 11 + ATHENA/bin/pyjwt | 11 + ATHENA/bin/pylint | 11 + ATHENA/bin/pyreverse | 11 + ATHENA/bin/pyrsa-decrypt | 11 + ATHENA/bin/pyrsa-encrypt | 11 + ATHENA/bin/pyrsa-keygen | 11 + ATHENA/bin/pyrsa-priv2pub | 11 + ATHENA/bin/pyrsa-sign | 11 + ATHENA/bin/pyrsa-verify | 11 + ATHENA/bin/pytest | 11 + ATHENA/bin/python | 1 + ATHENA/bin/python-config | 78 +++++++ ATHENA/bin/python3 | 1 + ATHENA/bin/python3.7 | Bin 0 -> 12552 bytes ATHENA/bin/symilar | 11 + ATHENA/bin/upgrade-requirements | 11 + ATHENA/bin/upreq | 11 + ATHENA/bin/wheel | 11 + ATHENA/bin/yapf | 11 + ATHENA/include/python3.7m | 1 + .../apps/articles/migrations/0001_initial.py | 96 +++++++++ .../migrations/0002_auto_20181220_1318.py | 84 ++++++++ .../articles/migrations/0003_reportarticle.py | 29 +++ .../migrations/0004_auto_20181220_1406.py | 18 ++ authors/apps/articles/models.py | 19 +- authors/apps/articles/renderers.py | 32 +++ authors/apps/articles/serializers.py | 21 +- authors/apps/articles/test/base.py | 14 ++ .../apps/articles/test/test_ceate_articles.py | 190 +++++++++++++++++- authors/apps/articles/urls.py | 16 +- authors/apps/articles/views.py | 142 ++++++++++--- .../authentication/migrations/0001_initial.py | 37 ++++ authors/apps/authentication/serializers.py | 6 + .../apps/profiles/migrations/0001_initial.py | 34 ++++ authors/apps/profiles/serializers.py | 3 + .../apps/profiles/test/test_create_profile.py | 41 ++++ authors/apps/profiles/urls.py | 6 +- authors/apps/profiles/views.py | 26 ++- 69 files changed, 1662 insertions(+), 46 deletions(-) create mode 100644 ATHENA/bin/activate create mode 100644 ATHENA/bin/activate.csh create mode 100644 ATHENA/bin/activate.fish create mode 100644 ATHENA/bin/activate.ps1 create mode 100644 ATHENA/bin/activate_this.py create mode 100755 ATHENA/bin/autopep8 create mode 100755 ATHENA/bin/chardetect create mode 100755 ATHENA/bin/coverage create mode 100755 ATHENA/bin/coverage-3.7 create mode 100755 ATHENA/bin/coverage3 create mode 100755 ATHENA/bin/coveralls create mode 100755 ATHENA/bin/django-admin create mode 100755 ATHENA/bin/django-admin.py create mode 100755 ATHENA/bin/dotenv create mode 100755 ATHENA/bin/easy_install create mode 100755 ATHENA/bin/easy_install-3.7 create mode 100755 ATHENA/bin/epylint create mode 100755 ATHENA/bin/futurize create mode 100755 ATHENA/bin/gunicorn create mode 100755 ATHENA/bin/gunicorn_paster create mode 100755 ATHENA/bin/isort create mode 100755 ATHENA/bin/markdown2 create mode 100755 ATHENA/bin/pasteurize create mode 100755 ATHENA/bin/pep8 create mode 100755 ATHENA/bin/pip create mode 100755 ATHENA/bin/pip3 create mode 100755 ATHENA/bin/pip3.7 create mode 100755 ATHENA/bin/py.test create mode 100755 ATHENA/bin/pycodestyle create mode 100755 ATHENA/bin/pyjwt create mode 100755 ATHENA/bin/pylint create mode 100755 ATHENA/bin/pyreverse create mode 100755 ATHENA/bin/pyrsa-decrypt create mode 100755 ATHENA/bin/pyrsa-encrypt create mode 100755 ATHENA/bin/pyrsa-keygen create mode 100755 ATHENA/bin/pyrsa-priv2pub create mode 100755 ATHENA/bin/pyrsa-sign create mode 100755 ATHENA/bin/pyrsa-verify create mode 100755 ATHENA/bin/pytest create mode 120000 ATHENA/bin/python create mode 100755 ATHENA/bin/python-config create mode 120000 ATHENA/bin/python3 create mode 100755 ATHENA/bin/python3.7 create mode 100755 ATHENA/bin/symilar create mode 100755 ATHENA/bin/upgrade-requirements create mode 100755 ATHENA/bin/upreq create mode 100755 ATHENA/bin/wheel create mode 100755 ATHENA/bin/yapf create mode 120000 ATHENA/include/python3.7m create mode 100644 authors/apps/articles/migrations/0001_initial.py create mode 100644 authors/apps/articles/migrations/0002_auto_20181220_1318.py create mode 100644 authors/apps/articles/migrations/0003_reportarticle.py create mode 100644 authors/apps/articles/migrations/0004_auto_20181220_1406.py create mode 100644 authors/apps/authentication/migrations/0001_initial.py create mode 100644 authors/apps/profiles/migrations/0001_initial.py diff --git a/.DS_Store b/.DS_Store index 9c174558c19d36bc612495d7940f07af7230c741..2cb28a114970a21dab14a5988852eacd8cbad039 100644 GIT binary patch delta 42 ycmZn(XbG6$&&abeU^hP_&t@KhpKO~gBpetwFOW=U+t?7zxS3tyAKPRLiT?mGg$|_v delta 253 zcmZn(XbG6$&nU1lU^hRbz-AtSpKP}53>ge147m(B49N`n3}v1<`N>H+`AG~63<3-c zjN(9A<3AVxSquzlswYbbOkg)P)lo1uvY5PHz)>1azAU&XFDE}Q9jKFWGn2S8qcRIa e8AB>V9)?Aqfl6jTEZSI@!?u}S;U9I~rVRi`hef0S diff --git a/.gitignore b/.gitignore index 0104cba..f5c119d 100644 --- a/.gitignore +++ b/.gitignore @@ -96,3 +96,4 @@ db.sqlite3 .vscode/ .DS_Store *.swp +/migrations diff --git a/ATHENA/bin/activate b/ATHENA/bin/activate new file mode 100644 index 0000000..98b2679 --- /dev/null +++ b/ATHENA/bin/activate @@ -0,0 +1,78 @@ +# This file must be used with "source bin/activate" *from bash* +# you cannot run it directly + +deactivate () { + unset -f pydoc >/dev/null 2>&1 + + # reset old environment variables + # ! [ -z ${VAR+_} ] returns true if VAR is declared at all + if ! [ -z "${_OLD_VIRTUAL_PATH+_}" ] ; then + PATH="$_OLD_VIRTUAL_PATH" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if ! [ -z "${_OLD_VIRTUAL_PYTHONHOME+_}" ] ; then + PYTHONHOME="$_OLD_VIRTUAL_PYTHONHOME" + export PYTHONHOME + unset _OLD_VIRTUAL_PYTHONHOME + fi + + # This should detect bash and zsh, which have a hash command that must + # be called to get it to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + if [ -n "${BASH-}" ] || [ -n "${ZSH_VERSION-}" ] ; then + hash -r 2>/dev/null + fi + + if ! [ -z "${_OLD_VIRTUAL_PS1+_}" ] ; then + PS1="$_OLD_VIRTUAL_PS1" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + if [ ! "${1-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +VIRTUAL_ENV="/Users/henry/Desktop/ah-backend-athena/ATHENA" +export VIRTUAL_ENV + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/bin:$PATH" +export PATH + +# unset PYTHONHOME if set +if ! [ -z "${PYTHONHOME+_}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="$PYTHONHOME" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT-}" ] ; then + _OLD_VIRTUAL_PS1="$PS1" + if [ "x" != x ] ; then + PS1="$PS1" + else + PS1="(`basename \"$VIRTUAL_ENV\"`) $PS1" + fi + export PS1 +fi + +# Make sure to unalias pydoc if it's already there +alias pydoc 2>/dev/null >/dev/null && unalias pydoc + +pydoc () { + python -m pydoc "$@" +} + +# This should detect bash and zsh, which have a hash command that must +# be called to get it to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +if [ -n "${BASH-}" ] || [ -n "${ZSH_VERSION-}" ] ; then + hash -r 2>/dev/null +fi diff --git a/ATHENA/bin/activate.csh b/ATHENA/bin/activate.csh new file mode 100644 index 0000000..08d385e --- /dev/null +++ b/ATHENA/bin/activate.csh @@ -0,0 +1,42 @@ +# This file must be used with "source bin/activate.csh" *from csh*. +# You cannot run it directly. +# Created by Davide Di Blasi . + +set newline='\ +' + +alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH:q" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT:q" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate && unalias pydoc' + +# Unset irrelevant variables. +deactivate nondestructive + +setenv VIRTUAL_ENV "/Users/henry/Desktop/ah-backend-athena/ATHENA" + +set _OLD_VIRTUAL_PATH="$PATH:q" +setenv PATH "$VIRTUAL_ENV:q/bin:$PATH:q" + + + +if ("" != "") then + set env_name = "" +else + set env_name = "$VIRTUAL_ENV:t:q" +endif + +# Could be in a non-interactive environment, +# in which case, $prompt is undefined and we wouldn't +# care about the prompt anyway. +if ( $?prompt ) then + set _OLD_VIRTUAL_PROMPT="$prompt:q" +if ( "$prompt:q" =~ *"$newline:q"* ) then + : +else + set prompt = "[$env_name:q] $prompt:q" +endif +endif + +unset env_name + +alias pydoc python -m pydoc + +rehash diff --git a/ATHENA/bin/activate.fish b/ATHENA/bin/activate.fish new file mode 100644 index 0000000..c86e7ce --- /dev/null +++ b/ATHENA/bin/activate.fish @@ -0,0 +1,76 @@ +# This file must be used using `source bin/activate.fish` *within a running fish ( http://fishshell.com ) session*. +# Do not run it directly. + +function deactivate -d 'Exit virtualenv mode and return to the normal environment.' + # reset old environment variables + if test -n "$_OLD_VIRTUAL_PATH" + set -gx PATH $_OLD_VIRTUAL_PATH + set -e _OLD_VIRTUAL_PATH + end + + if test -n "$_OLD_VIRTUAL_PYTHONHOME" + set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME + set -e _OLD_VIRTUAL_PYTHONHOME + end + + if test -n "$_OLD_FISH_PROMPT_OVERRIDE" + # Set an empty local `$fish_function_path` to allow the removal of `fish_prompt` using `functions -e`. + set -l fish_function_path + + # Erase virtualenv's `fish_prompt` and restore the original. + functions -e fish_prompt + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + set -e _OLD_FISH_PROMPT_OVERRIDE + end + + set -e VIRTUAL_ENV + + if test "$argv[1]" != 'nondestructive' + # Self-destruct! + functions -e pydoc + functions -e deactivate + end +end + +# Unset irrelevant variables. +deactivate nondestructive + +set -gx VIRTUAL_ENV "/Users/henry/Desktop/ah-backend-athena/ATHENA" + +set -gx _OLD_VIRTUAL_PATH $PATH +set -gx PATH "$VIRTUAL_ENV/bin" $PATH + +# Unset `$PYTHONHOME` if set. +if set -q PYTHONHOME + set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME + set -e PYTHONHOME +end + +function pydoc + python -m pydoc $argv +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # Copy the current `fish_prompt` function as `_old_fish_prompt`. + functions -c fish_prompt _old_fish_prompt + + function fish_prompt + # Save the current $status, for fish_prompts that display it. + set -l old_status $status + + # Prompt override provided? + # If not, just prepend the environment name. + if test -n "" + printf '%s%s' "" (set_color normal) + else + printf '%s(%s) ' (set_color normal) (basename "$VIRTUAL_ENV") + end + + # Restore the original $status + echo "exit $old_status" | source + _old_fish_prompt + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" +end diff --git a/ATHENA/bin/activate.ps1 b/ATHENA/bin/activate.ps1 new file mode 100644 index 0000000..89dbec6 --- /dev/null +++ b/ATHENA/bin/activate.ps1 @@ -0,0 +1,150 @@ +# This file must be dot sourced from PoSh; you cannot run it +# directly. Do this: . ./activate.ps1 + +# FIXME: clean up unused vars. +$script:THIS_PATH = $myinvocation.mycommand.path +$script:BASE_DIR = split-path (resolve-path "$THIS_PATH/..") -Parent +$script:DIR_NAME = split-path $BASE_DIR -Leaf + +function global:deactivate ( [switch] $NonDestructive ){ + + if ( test-path variable:_OLD_VIRTUAL_PATH ) { + $env:PATH = $variable:_OLD_VIRTUAL_PATH + remove-variable "_OLD_VIRTUAL_PATH" -scope global + } + + if ( test-path function:_old_virtual_prompt ) { + $function:prompt = $function:_old_virtual_prompt + remove-item function:\_old_virtual_prompt + } + + if ($env:VIRTUAL_ENV) { + $old_env = split-path $env:VIRTUAL_ENV -leaf + remove-item env:VIRTUAL_ENV -erroraction silentlycontinue + } + + if ( !$NonDestructive ) { + # Self destruct! + remove-item function:deactivate + } +} + +# unset irrelevant variables +deactivate -nondestructive + +$VIRTUAL_ENV = $BASE_DIR +$env:VIRTUAL_ENV = $VIRTUAL_ENV + +$global:_OLD_VIRTUAL_PATH = $env:PATH +$env:PATH = "$env:VIRTUAL_ENV/bin:" + $env:PATH +if (! $env:VIRTUAL_ENV_DISABLE_PROMPT) { + function global:_old_virtual_prompt { "" } + $function:_old_virtual_prompt = $function:prompt + function global:prompt { + # Add a prefix to the current prompt, but don't discard it. + write-host "($(split-path $env:VIRTUAL_ENV -leaf)) " -nonewline + & $function:_old_virtual_prompt + } +} + +# SIG # Begin signature block +# MIISeAYJKoZIhvcNAQcCoIISaTCCEmUCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB +# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR +# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUS5reBwSg3zOUwhXf2jPChZzf +# yPmggg6tMIIGcDCCBFigAwIBAgIBJDANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQG +# EwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERp +# Z2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2Vy +# dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjIwMTQ2WhcNMTcxMDI0MjIw +# MTQ2WjCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzAp +# BgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNV +# BAMTL1N0YXJ0Q29tIENsYXNzIDIgUHJpbWFyeSBJbnRlcm1lZGlhdGUgT2JqZWN0 +# IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyiOLIjUemqAbPJ1J +# 0D8MlzgWKbr4fYlbRVjvhHDtfhFN6RQxq0PjTQxRgWzwFQNKJCdU5ftKoM5N4YSj +# Id6ZNavcSa6/McVnhDAQm+8H3HWoD030NVOxbjgD/Ih3HaV3/z9159nnvyxQEckR +# ZfpJB2Kfk6aHqW3JnSvRe+XVZSufDVCe/vtxGSEwKCaNrsLc9pboUoYIC3oyzWoU +# TZ65+c0H4paR8c8eK/mC914mBo6N0dQ512/bkSdaeY9YaQpGtW/h/W/FkbQRT3sC +# pttLVlIjnkuY4r9+zvqhToPjxcfDYEf+XD8VGkAqle8Aa8hQ+M1qGdQjAye8OzbV +# uUOw7wIDAQABo4IB6TCCAeUwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +# AQYwHQYDVR0OBBYEFNBOD0CZbLhLGW87KLjg44gHNKq3MB8GA1UdIwQYMBaAFE4L +# 7xqkQFulF2mHMMo0aEPQQa7yMD0GCCsGAQUFBwEBBDEwLzAtBggrBgEFBQcwAoYh +# aHR0cDovL3d3dy5zdGFydHNzbC5jb20vc2ZzY2EuY3J0MFsGA1UdHwRUMFIwJ6Al +# oCOGIWh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3Nmc2NhLmNybDAnoCWgI4YhaHR0 +# cDovL2NybC5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMIGABgNVHSAEeTB3MHUGCysG +# AQQBgbU3AQIBMGYwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29t +# L3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t +# L2ludGVybWVkaWF0ZS5wZGYwEQYJYIZIAYb4QgEBBAQDAgABMFAGCWCGSAGG+EIB +# DQRDFkFTdGFydENvbSBDbGFzcyAyIFByaW1hcnkgSW50ZXJtZWRpYXRlIE9iamVj +# dCBTaWduaW5nIENlcnRpZmljYXRlczANBgkqhkiG9w0BAQUFAAOCAgEAcnMLA3Va +# N4OIE9l4QT5OEtZy5PByBit3oHiqQpgVEQo7DHRsjXD5H/IyTivpMikaaeRxIv95 +# baRd4hoUcMwDj4JIjC3WA9FoNFV31SMljEZa66G8RQECdMSSufgfDYu1XQ+cUKxh +# D3EtLGGcFGjjML7EQv2Iol741rEsycXwIXcryxeiMbU2TPi7X3elbwQMc4JFlJ4B +# y9FhBzuZB1DV2sN2irGVbC3G/1+S2doPDjL1CaElwRa/T0qkq2vvPxUgryAoCppU +# FKViw5yoGYC+z1GaesWWiP1eFKAL0wI7IgSvLzU3y1Vp7vsYaxOVBqZtebFTWRHt +# XjCsFrrQBngt0d33QbQRI5mwgzEp7XJ9xu5d6RVWM4TPRUsd+DDZpBHm9mszvi9g +# VFb2ZG7qRRXCSqys4+u/NLBPbXi/m/lU00cODQTlC/euwjk9HQtRrXQ/zqsBJS6U +# J+eLGw1qOfj+HVBl/ZQpfoLk7IoWlRQvRL1s7oirEaqPZUIWY/grXq9r6jDKAp3L +# ZdKQpPOnnogtqlU4f7/kLjEJhrrc98mrOWmVMK/BuFRAfQ5oDUMnVmCzAzLMjKfG +# cVW/iMew41yfhgKbwpfzm3LBr1Zv+pEBgcgW6onRLSAn3XHM0eNtz+AkxH6rRf6B +# 2mYhLEEGLapH8R1AMAo4BbVFOZR5kXcMCwowggg1MIIHHaADAgECAgIEuDANBgkq +# hkiG9w0BAQUFADCBjDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0 +# ZC4xKzApBgNVBAsTIlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcx +# ODA2BgNVBAMTL1N0YXJ0Q29tIENsYXNzIDIgUHJpbWFyeSBJbnRlcm1lZGlhdGUg +# T2JqZWN0IENBMB4XDTExMTIwMzE1MzQxOVoXDTEzMTIwMzE0NTgwN1owgYwxIDAe +# BgNVBA0TFzU4MTc5Ni1HaDd4Zkp4a3hRU0lPNEUwMQswCQYDVQQGEwJERTEPMA0G +# A1UECBMGQmVybGluMQ8wDQYDVQQHEwZCZXJsaW4xFjAUBgNVBAMTDUphbm5pcyBM +# ZWlkZWwxITAfBgkqhkiG9w0BCQEWEmphbm5pc0BsZWlkZWwuaW5mbzCCAiIwDQYJ +# KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMcPeABYdN7nPq/AkZ/EkyUBGx/l2Yui +# Lfm8ZdLG0ulMb/kQL3fRY7sUjYPyn9S6PhqqlFnNoGHJvbbReCdUC9SIQYmOEjEA +# raHfb7MZU10NjO4U2DdGucj2zuO5tYxKizizOJF0e4yRQZVxpUGdvkW/+GLjCNK5 +# L7mIv3Z1dagxDKHYZT74HXiS4VFUwHF1k36CwfM2vsetdm46bdgSwV+BCMmZICYT +# IJAS9UQHD7kP4rik3bFWjUx08NtYYFAVOd/HwBnemUmJe4j3IhZHr0k1+eDG8hDH +# KVvPgLJIoEjC4iMFk5GWsg5z2ngk0LLu3JZMtckHsnnmBPHQK8a3opUNd8hdMNJx +# gOwKjQt2JZSGUdIEFCKVDqj0FmdnDMPfwy+FNRtpBMl1sz78dUFhSrnM0D8NXrqa +# 4rG+2FoOXlmm1rb6AFtpjAKksHRpYcPk2DPGWp/1sWB+dUQkS3gOmwFzyqeTuXpT +# 0juqd3iAxOGx1VRFQ1VHLLf3AzV4wljBau26I+tu7iXxesVucSdsdQu293jwc2kN +# xK2JyHCoZH+RyytrwS0qw8t7rMOukU9gwP8mn3X6mgWlVUODMcHTULjSiCEtvyZ/ +# aafcwjUbt4ReEcnmuZtWIha86MTCX7U7e+cnpWG4sIHPnvVTaz9rm8RyBkIxtFCB +# nQ3FnoQgyxeJAgMBAAGjggOdMIIDmTAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIH +# gDAuBgNVHSUBAf8EJDAiBggrBgEFBQcDAwYKKwYBBAGCNwIBFQYKKwYBBAGCNwoD +# DTAdBgNVHQ4EFgQUWyCgrIWo8Ifvvm1/YTQIeMU9nc8wHwYDVR0jBBgwFoAU0E4P +# QJlsuEsZbzsouODjiAc0qrcwggIhBgNVHSAEggIYMIICFDCCAhAGCysGAQQBgbU3 +# AQICMIIB/zAuBggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9s +# aWN5LnBkZjA0BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50 +# ZXJtZWRpYXRlLnBkZjCB9wYIKwYBBQUHAgIwgeowJxYgU3RhcnRDb20gQ2VydGlm +# aWNhdGlvbiBBdXRob3JpdHkwAwIBARqBvlRoaXMgY2VydGlmaWNhdGUgd2FzIGlz +# c3VlZCBhY2NvcmRpbmcgdG8gdGhlIENsYXNzIDIgVmFsaWRhdGlvbiByZXF1aXJl +# bWVudHMgb2YgdGhlIFN0YXJ0Q29tIENBIHBvbGljeSwgcmVsaWFuY2Ugb25seSBm +# b3IgdGhlIGludGVuZGVkIHB1cnBvc2UgaW4gY29tcGxpYW5jZSBvZiB0aGUgcmVs +# eWluZyBwYXJ0eSBvYmxpZ2F0aW9ucy4wgZwGCCsGAQUFBwICMIGPMCcWIFN0YXJ0 +# Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MAMCAQIaZExpYWJpbGl0eSBhbmQg +# d2FycmFudGllcyBhcmUgbGltaXRlZCEgU2VlIHNlY3Rpb24gIkxlZ2FsIGFuZCBM +# aW1pdGF0aW9ucyIgb2YgdGhlIFN0YXJ0Q29tIENBIHBvbGljeS4wNgYDVR0fBC8w +# LTAroCmgJ4YlaHR0cDovL2NybC5zdGFydHNzbC5jb20vY3J0YzItY3JsLmNybDCB +# iQYIKwYBBQUHAQEEfTB7MDcGCCsGAQUFBzABhitodHRwOi8vb2NzcC5zdGFydHNz +# bC5jb20vc3ViL2NsYXNzMi9jb2RlL2NhMEAGCCsGAQUFBzAChjRodHRwOi8vYWlh +# LnN0YXJ0c3NsLmNvbS9jZXJ0cy9zdWIuY2xhc3MyLmNvZGUuY2EuY3J0MCMGA1Ud +# EgQcMBqGGGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tLzANBgkqhkiG9w0BAQUFAAOC +# AQEAhrzEV6zwoEtKjnFRhCsjwiPykVpo5Eiye77Ve801rQDiRKgSCCiW6g3HqedL +# OtaSs65Sj2pm3Viea4KR0TECLcbCTgsdaHqw2x1yXwWBQWZEaV6EB05lIwfr94P1 +# SFpV43zkuc+bbmA3+CRK45LOcCNH5Tqq7VGTCAK5iM7tvHwFlbQRl+I6VEL2mjpF +# NsuRjDOVrv/9qw/a22YJ9R7Y1D0vUSs3IqZx2KMUaYDP7H2mSRxJO2nADQZBtriF +# gTyfD3lYV12MlIi5CQwe3QC6DrrfSMP33i5Wa/OFJiQ27WPxmScYVhiqozpImFT4 +# PU9goiBv9RKXdgTmZE1PN0NQ5jGCAzUwggMxAgEBMIGTMIGMMQswCQYDVQQGEwJJ +# TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0 +# YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg +# MiBQcmltYXJ5IEludGVybWVkaWF0ZSBPYmplY3QgQ0ECAgS4MAkGBSsOAwIaBQCg +# eDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEE +# AYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJ +# BDEWBBRVGw0FDSiaIi38dWteRUAg/9Pr6DANBgkqhkiG9w0BAQEFAASCAgCInvOZ +# FdaNFzbf6trmFDZKMojyx3UjKMCqNjHVBbuKY0qXwFC/ElYDV1ShJ2CBZbdurydO +# OQ6cIQ0KREOCwmX/xB49IlLHHUxNhEkVv7HGU3EKAFf9IBt9Yr7jikiR9cjIsfHK +# 4cjkoKJL7g28yEpLLkHt1eo37f1Ga9lDWEa5Zq3U5yX+IwXhrUBm1h8Xr033FhTR +# VEpuSz6LHtbrL/zgJnCzJ2ahjtJoYevdcWiNXffosJHFaSfYDDbiNsPRDH/1avmb +# 5j/7BhP8BcBaR6Fp8tFbNGIcWHHGcjqLMnTc4w13b7b4pDhypqElBa4+lCmwdvv9 +# GydYtRgPz8GHeoBoKj30YBlMzRIfFYaIFGIC4Ai3UEXkuH9TxYohVbGm/W0Kl4Lb +# RJ1FwiVcLcTOJdgNId2vQvKc+jtNrjcg5SP9h2v/C4aTx8tyc6tE3TOPh2f9b8DL +# S+SbVArJpuJqrPTxDDoO1QNjTgLcdVYeZDE+r/NjaGZ6cMSd8db3EaG3ijD/0bud +# SItbm/OlNVbQOFRR76D+ZNgPcU5iNZ3bmvQQIg6aSB9MHUpIE/SeCkNl9YeVk1/1 +# GFULgNMRmIYP4KLvu9ylh5Gu3hvD5VNhH6+FlXANwFy07uXks5uF8mfZVxVCnodG +# xkNCx+6PsrA5Z7WP4pXcmYnMn97npP/Q9EHJWw== +# SIG # End signature block diff --git a/ATHENA/bin/activate_this.py b/ATHENA/bin/activate_this.py new file mode 100644 index 0000000..444d3fd --- /dev/null +++ b/ATHENA/bin/activate_this.py @@ -0,0 +1,36 @@ +"""By using execfile(this_file, dict(__file__=this_file)) you will +activate this virtualenv environment. + +This can be used when you must use an existing Python interpreter, not +the virtualenv bin/python +""" + +try: + __file__ +except NameError: + raise AssertionError( + "You must run this like execfile('path/to/activate_this.py', dict(__file__='path/to/activate_this.py'))" + ) +import os +import site +import sys + +old_os_path = os.environ.get("PATH", "") +os.environ["PATH"] = os.path.dirname(os.path.abspath(__file__)) + os.pathsep + old_os_path +base = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +if sys.platform == "win32": + site_packages = os.path.join(base, "Lib", "site-packages") +else: + site_packages = os.path.join(base, "lib", "python%s" % sys.version[:3], "site-packages") +prev_sys_path = list(sys.path) + +site.addsitedir(site_packages) +sys.real_prefix = sys.prefix +sys.prefix = base +# Move the added items to the front of the path: +new_sys_path = [] +for item in list(sys.path): + if item not in prev_sys_path: + new_sys_path.append(item) + sys.path.remove(item) +sys.path[:0] = new_sys_path diff --git a/ATHENA/bin/autopep8 b/ATHENA/bin/autopep8 new file mode 100755 index 0000000..2d8394c --- /dev/null +++ b/ATHENA/bin/autopep8 @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from autopep8 import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/chardetect b/ATHENA/bin/chardetect new file mode 100755 index 0000000..5467ad5 --- /dev/null +++ b/ATHENA/bin/chardetect @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from chardet.cli.chardetect import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/coverage b/ATHENA/bin/coverage new file mode 100755 index 0000000..01e67cc --- /dev/null +++ b/ATHENA/bin/coverage @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from coverage.cmdline import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/coverage-3.7 b/ATHENA/bin/coverage-3.7 new file mode 100755 index 0000000..01e67cc --- /dev/null +++ b/ATHENA/bin/coverage-3.7 @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from coverage.cmdline import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/coverage3 b/ATHENA/bin/coverage3 new file mode 100755 index 0000000..01e67cc --- /dev/null +++ b/ATHENA/bin/coverage3 @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from coverage.cmdline import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/coveralls b/ATHENA/bin/coveralls new file mode 100755 index 0000000..6c817e8 --- /dev/null +++ b/ATHENA/bin/coveralls @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from coveralls.cli import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/django-admin b/ATHENA/bin/django-admin new file mode 100755 index 0000000..1bd1501 --- /dev/null +++ b/ATHENA/bin/django-admin @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from django.core.management import execute_from_command_line + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(execute_from_command_line()) diff --git a/ATHENA/bin/django-admin.py b/ATHENA/bin/django-admin.py new file mode 100755 index 0000000..d4d78df --- /dev/null +++ b/ATHENA/bin/django-admin.py @@ -0,0 +1,5 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 +from django.core import management + +if __name__ == "__main__": + management.execute_from_command_line() diff --git a/ATHENA/bin/dotenv b/ATHENA/bin/dotenv new file mode 100755 index 0000000..de450aa --- /dev/null +++ b/ATHENA/bin/dotenv @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from dotenv.cli import cli + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(cli()) diff --git a/ATHENA/bin/easy_install b/ATHENA/bin/easy_install new file mode 100755 index 0000000..1f7f016 --- /dev/null +++ b/ATHENA/bin/easy_install @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from setuptools.command.easy_install import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/easy_install-3.7 b/ATHENA/bin/easy_install-3.7 new file mode 100755 index 0000000..1f7f016 --- /dev/null +++ b/ATHENA/bin/easy_install-3.7 @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from setuptools.command.easy_install import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/epylint b/ATHENA/bin/epylint new file mode 100755 index 0000000..1e8a57c --- /dev/null +++ b/ATHENA/bin/epylint @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from pylint import run_epylint + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(run_epylint()) diff --git a/ATHENA/bin/futurize b/ATHENA/bin/futurize new file mode 100755 index 0000000..e3ae583 --- /dev/null +++ b/ATHENA/bin/futurize @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from libfuturize.main import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/gunicorn b/ATHENA/bin/gunicorn new file mode 100755 index 0000000..96fa6a7 --- /dev/null +++ b/ATHENA/bin/gunicorn @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from gunicorn.app.wsgiapp import run + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(run()) diff --git a/ATHENA/bin/gunicorn_paster b/ATHENA/bin/gunicorn_paster new file mode 100755 index 0000000..9bafd63 --- /dev/null +++ b/ATHENA/bin/gunicorn_paster @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from gunicorn.app.pasterapp import run + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(run()) diff --git a/ATHENA/bin/isort b/ATHENA/bin/isort new file mode 100755 index 0000000..5932010 --- /dev/null +++ b/ATHENA/bin/isort @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from isort.main import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/markdown2 b/ATHENA/bin/markdown2 new file mode 100755 index 0000000..eed6e7e --- /dev/null +++ b/ATHENA/bin/markdown2 @@ -0,0 +1,18 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +import sys +from os.path import join, dirname, exists + +# Use the local markdown2.py if we are in the source tree. +source_tree_markdown2 = join(dirname(__file__), "..", "lib", "markdown2.py") +if exists(source_tree_markdown2): + sys.path.insert(0, dirname(source_tree_markdown2)) + try: + from markdown2 import main + finally: + del sys.path[0] +else: + from markdown2 import main + +if __name__ == "__main__": + sys.exit( main(sys.argv) ) diff --git a/ATHENA/bin/pasteurize b/ATHENA/bin/pasteurize new file mode 100755 index 0000000..e457941 --- /dev/null +++ b/ATHENA/bin/pasteurize @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from libpasteurize.main import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/pep8 b/ATHENA/bin/pep8 new file mode 100755 index 0000000..d15e4f7 --- /dev/null +++ b/ATHENA/bin/pep8 @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from pep8 import _main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(_main()) diff --git a/ATHENA/bin/pip b/ATHENA/bin/pip new file mode 100755 index 0000000..4b03baf --- /dev/null +++ b/ATHENA/bin/pip @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from pip._internal import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/pip3 b/ATHENA/bin/pip3 new file mode 100755 index 0000000..4b03baf --- /dev/null +++ b/ATHENA/bin/pip3 @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from pip._internal import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/pip3.7 b/ATHENA/bin/pip3.7 new file mode 100755 index 0000000..4b03baf --- /dev/null +++ b/ATHENA/bin/pip3.7 @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from pip._internal import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/py.test b/ATHENA/bin/py.test new file mode 100755 index 0000000..94ea4c1 --- /dev/null +++ b/ATHENA/bin/py.test @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from pytest import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/pycodestyle b/ATHENA/bin/pycodestyle new file mode 100755 index 0000000..d7a4b40 --- /dev/null +++ b/ATHENA/bin/pycodestyle @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from pycodestyle import _main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(_main()) diff --git a/ATHENA/bin/pyjwt b/ATHENA/bin/pyjwt new file mode 100755 index 0000000..3f45efe --- /dev/null +++ b/ATHENA/bin/pyjwt @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from jwt.__main__ import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/pylint b/ATHENA/bin/pylint new file mode 100755 index 0000000..ea8fbc4 --- /dev/null +++ b/ATHENA/bin/pylint @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from pylint import run_pylint + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(run_pylint()) diff --git a/ATHENA/bin/pyreverse b/ATHENA/bin/pyreverse new file mode 100755 index 0000000..1b343dc --- /dev/null +++ b/ATHENA/bin/pyreverse @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from pylint import run_pyreverse + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(run_pyreverse()) diff --git a/ATHENA/bin/pyrsa-decrypt b/ATHENA/bin/pyrsa-decrypt new file mode 100755 index 0000000..750d664 --- /dev/null +++ b/ATHENA/bin/pyrsa-decrypt @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from rsa.cli import decrypt + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(decrypt()) diff --git a/ATHENA/bin/pyrsa-encrypt b/ATHENA/bin/pyrsa-encrypt new file mode 100755 index 0000000..e39424e --- /dev/null +++ b/ATHENA/bin/pyrsa-encrypt @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from rsa.cli import encrypt + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(encrypt()) diff --git a/ATHENA/bin/pyrsa-keygen b/ATHENA/bin/pyrsa-keygen new file mode 100755 index 0000000..93c7919 --- /dev/null +++ b/ATHENA/bin/pyrsa-keygen @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from rsa.cli import keygen + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(keygen()) diff --git a/ATHENA/bin/pyrsa-priv2pub b/ATHENA/bin/pyrsa-priv2pub new file mode 100755 index 0000000..480fb65 --- /dev/null +++ b/ATHENA/bin/pyrsa-priv2pub @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from rsa.util import private_to_public + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(private_to_public()) diff --git a/ATHENA/bin/pyrsa-sign b/ATHENA/bin/pyrsa-sign new file mode 100755 index 0000000..82581a2 --- /dev/null +++ b/ATHENA/bin/pyrsa-sign @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from rsa.cli import sign + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(sign()) diff --git a/ATHENA/bin/pyrsa-verify b/ATHENA/bin/pyrsa-verify new file mode 100755 index 0000000..b13f32b --- /dev/null +++ b/ATHENA/bin/pyrsa-verify @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from rsa.cli import verify + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(verify()) diff --git a/ATHENA/bin/pytest b/ATHENA/bin/pytest new file mode 100755 index 0000000..94ea4c1 --- /dev/null +++ b/ATHENA/bin/pytest @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from pytest import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/python b/ATHENA/bin/python new file mode 120000 index 0000000..940bee3 --- /dev/null +++ b/ATHENA/bin/python @@ -0,0 +1 @@ +python3.7 \ No newline at end of file diff --git a/ATHENA/bin/python-config b/ATHENA/bin/python-config new file mode 100755 index 0000000..949830b --- /dev/null +++ b/ATHENA/bin/python-config @@ -0,0 +1,78 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python + +import sys +import getopt +import sysconfig + +valid_opts = ['prefix', 'exec-prefix', 'includes', 'libs', 'cflags', + 'ldflags', 'help'] + +if sys.version_info >= (3, 2): + valid_opts.insert(-1, 'extension-suffix') + valid_opts.append('abiflags') +if sys.version_info >= (3, 3): + valid_opts.append('configdir') + + +def exit_with_usage(code=1): + sys.stderr.write("Usage: {0} [{1}]\n".format( + sys.argv[0], '|'.join('--'+opt for opt in valid_opts))) + sys.exit(code) + +try: + opts, args = getopt.getopt(sys.argv[1:], '', valid_opts) +except getopt.error: + exit_with_usage() + +if not opts: + exit_with_usage() + +pyver = sysconfig.get_config_var('VERSION') +getvar = sysconfig.get_config_var + +opt_flags = [flag for (flag, val) in opts] + +if '--help' in opt_flags: + exit_with_usage(code=0) + +for opt in opt_flags: + if opt == '--prefix': + print(sysconfig.get_config_var('prefix')) + + elif opt == '--exec-prefix': + print(sysconfig.get_config_var('exec_prefix')) + + elif opt in ('--includes', '--cflags'): + flags = ['-I' + sysconfig.get_path('include'), + '-I' + sysconfig.get_path('platinclude')] + if opt == '--cflags': + flags.extend(getvar('CFLAGS').split()) + print(' '.join(flags)) + + elif opt in ('--libs', '--ldflags'): + abiflags = getattr(sys, 'abiflags', '') + libs = ['-lpython' + pyver + abiflags] + libs += getvar('LIBS').split() + libs += getvar('SYSLIBS').split() + # add the prefix/lib/pythonX.Y/config dir, but only if there is no + # shared library in prefix/lib/. + if opt == '--ldflags': + if not getvar('Py_ENABLE_SHARED'): + libs.insert(0, '-L' + getvar('LIBPL')) + if not getvar('PYTHONFRAMEWORK'): + libs.extend(getvar('LINKFORSHARED').split()) + print(' '.join(libs)) + + elif opt == '--extension-suffix': + ext_suffix = sysconfig.get_config_var('EXT_SUFFIX') + if ext_suffix is None: + ext_suffix = sysconfig.get_config_var('SO') + print(ext_suffix) + + elif opt == '--abiflags': + if not getattr(sys, 'abiflags', None): + exit_with_usage() + print(sys.abiflags) + + elif opt == '--configdir': + print(sysconfig.get_config_var('LIBPL')) diff --git a/ATHENA/bin/python3 b/ATHENA/bin/python3 new file mode 120000 index 0000000..940bee3 --- /dev/null +++ b/ATHENA/bin/python3 @@ -0,0 +1 @@ +python3.7 \ No newline at end of file diff --git a/ATHENA/bin/python3.7 b/ATHENA/bin/python3.7 new file mode 100755 index 0000000000000000000000000000000000000000..b42712bc3f9098279c5fac23525e2709cddf212c GIT binary patch literal 12552 zcmeI2&rcIU6vw9u(ja2dgZL{pM2vXY1ua5|2`x~BhzbJ6n3&1dF6oAL+w5)wjTbH^ znqa~SFa8N0^yW>E-ux%j$ia(8O|0LyJ6pEp$KB+;^zH0>^XAR$XLc{0_vQD`za2uv zjta4HL?hV0orjW8{!nSJ4%@GHDi4i|N;ixovFSc-7=!-SiGfVoMm2(WIrcXOY$y_TttFAs-cFgH=)y^B9RkpR2 zut$GrIxak}o@t3e?mhE#V3(n3bKQJe^^9E6loi7(=$fW$^EIzfwuLqnoi=dpH{A_w zL{~%nc}648)BgD@wkx*F5lCT!9k50``U8hXG~NezPzECcp%k025#W zOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2{3^uf#sQ(-=6G{r`}IT+;guknrJeM z_5NkFTXg;=cD~o^_2B&Q0@;vgOJ{R*c9%j+`Wp8nbWi7{T{z=P_@|HL-M#TGT;3wy zKky43+%f?szyz286JP>NfC(@GCcp%k025#W|2=`8zQh7O#OX8@5BtUNGKYF|6t6Eh zVoNxQQ)$%x*W|Kot=}~)8$MrRQkDubsLC}_?{3hLGY6J3Z;l7UM$p`XPGk)#>-TG< zPsXUCHu&Fx>WlIJLn9B>+rn;?dQ*oo(qYhkD`{Tyo@aB6yfdcj!#9Ug!>Q}Y`495V B;|%}+ literal 0 HcmV?d00001 diff --git a/ATHENA/bin/symilar b/ATHENA/bin/symilar new file mode 100755 index 0000000..24dd630 --- /dev/null +++ b/ATHENA/bin/symilar @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from pylint import run_symilar + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(run_symilar()) diff --git a/ATHENA/bin/upgrade-requirements b/ATHENA/bin/upgrade-requirements new file mode 100755 index 0000000..ce12723 --- /dev/null +++ b/ATHENA/bin/upgrade-requirements @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from upgrade_requirements import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/upreq b/ATHENA/bin/upreq new file mode 100755 index 0000000..ce12723 --- /dev/null +++ b/ATHENA/bin/upreq @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from upgrade_requirements import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/wheel b/ATHENA/bin/wheel new file mode 100755 index 0000000..eafbb1d --- /dev/null +++ b/ATHENA/bin/wheel @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from wheel.cli import main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/ATHENA/bin/yapf b/ATHENA/bin/yapf new file mode 100755 index 0000000..502ca2f --- /dev/null +++ b/ATHENA/bin/yapf @@ -0,0 +1,11 @@ +#!/Users/henry/Desktop/ah-backend-athena/ATHENA/bin/python3.7 + +# -*- coding: utf-8 -*- +import re +import sys + +from yapf import run_main + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit(run_main()) diff --git a/ATHENA/include/python3.7m b/ATHENA/include/python3.7m new file mode 120000 index 0000000..10d1d16 --- /dev/null +++ b/ATHENA/include/python3.7m @@ -0,0 +1 @@ +/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/include/python3.7m \ No newline at end of file diff --git a/authors/apps/articles/migrations/0001_initial.py b/authors/apps/articles/migrations/0001_initial.py new file mode 100644 index 0000000..e55f700 --- /dev/null +++ b/authors/apps/articles/migrations/0001_initial.py @@ -0,0 +1,96 @@ +# Generated by Django 2.1.3 on 2018-12-20 13:18 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Article', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(db_index=True, max_length=255)), + ('body', models.TextField(db_index=True)), + ('description', models.CharField(db_index=True, max_length=255, null=True)), + ('slug', models.SlugField(max_length=255, unique=True)), + ('published', models.BooleanField(default=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('favourited', models.BooleanField(default=False)), + ('favouriteCount', models.IntegerField(default=0)), + ('likes_count', models.IntegerField(default=0)), + ('read_time', models.IntegerField(default=0)), + ('view_count', models.IntegerField(default=0)), + ('read_count', models.IntegerField(default=0)), + ], + options={ + 'ordering': ['-created_at', '-updated_at'], + }, + ), + migrations.CreateModel( + name='ArticleImg', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('image_url', models.URLField(blank=True, null=True)), + ('description', models.CharField(db_index=True, max_length=255)), + ('position_in_body_before', models.IntegerField(null=True)), + ], + ), + migrations.CreateModel( + name='ComentLikes', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('like', models.BooleanField()), + ], + ), + migrations.CreateModel( + name='Comments', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('comment_body', models.TextField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now_add=True)), + ('likes_count', models.IntegerField(default=0)), + ], + options={ + 'get_latest_by': ['created_at'], + }, + ), + migrations.CreateModel( + name='Favourites', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('favourite', models.BooleanField(default=False)), + ], + ), + migrations.CreateModel( + name='Likes', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('like', models.BooleanField()), + ], + ), + migrations.CreateModel( + name='Readings', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('read_count', models.IntegerField(default=0)), + ('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='articles.Article')), + ], + ), + migrations.CreateModel( + name='Tag', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('tag', models.CharField(max_length=255)), + ('slug', models.SlugField(unique=True)), + ], + ), + ] diff --git a/authors/apps/articles/migrations/0002_auto_20181220_1318.py b/authors/apps/articles/migrations/0002_auto_20181220_1318.py new file mode 100644 index 0000000..fa778e7 --- /dev/null +++ b/authors/apps/articles/migrations/0002_auto_20181220_1318.py @@ -0,0 +1,84 @@ +# Generated by Django 2.1.3 on 2018-12-20 13:18 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('profiles', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('articles', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='readings', + name='author', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='likes', + name='article', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='articles.Article'), + ), + migrations.AddField( + model_name='likes', + name='profile', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='profiles.Profile'), + ), + migrations.AddField( + model_name='favourites', + name='article', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='article_id', to='articles.Article'), + ), + migrations.AddField( + model_name='favourites', + name='profile', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='profiles.Profile'), + ), + migrations.AddField( + model_name='comments', + name='article', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='articles.Article'), + ), + migrations.AddField( + model_name='comments', + name='author', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='comments', + name='parent', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='articles.Comments'), + ), + migrations.AddField( + model_name='comentlikes', + name='comment', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='articles.Comments'), + ), + migrations.AddField( + model_name='comentlikes', + name='profile', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='profiles.Profile'), + ), + migrations.AddField( + model_name='articleimg', + name='article', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='articles.Article'), + ), + migrations.AddField( + model_name='article', + name='author', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='profiles.Profile'), + ), + migrations.AddField( + model_name='article', + name='tags', + field=models.ManyToManyField(related_name='articles', to='articles.Tag'), + ), + ] diff --git a/authors/apps/articles/migrations/0003_reportarticle.py b/authors/apps/articles/migrations/0003_reportarticle.py new file mode 100644 index 0000000..7d73d84 --- /dev/null +++ b/authors/apps/articles/migrations/0003_reportarticle.py @@ -0,0 +1,29 @@ +# Generated by Django 2.1.3 on 2018-12-20 13:51 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('profiles', '0001_initial'), + ('articles', '0002_auto_20181220_1318'), + ] + + operations = [ + migrations.CreateModel( + name='ReportArticle', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('reason', models.CharField(db_index=True, max_length=255)), + ('reported_at', models.DateTimeField(auto_now_add=True)), + ('article_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='articles.Article')), + ('article_slug', models.ForeignKey(db_column='slug', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='a_slug', to='articles.Article', to_field='slug')), + ('reported_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='profiles.Profile')), + ], + options={ + 'ordering': ['-reported_at'], + }, + ), + ] diff --git a/authors/apps/articles/migrations/0004_auto_20181220_1406.py b/authors/apps/articles/migrations/0004_auto_20181220_1406.py new file mode 100644 index 0000000..19a44e0 --- /dev/null +++ b/authors/apps/articles/migrations/0004_auto_20181220_1406.py @@ -0,0 +1,18 @@ +# Generated by Django 2.1.3 on 2018-12-20 14:06 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('articles', '0003_reportarticle'), + ] + + operations = [ + migrations.AlterField( + model_name='article', + name='published', + field=models.BooleanField(default=True), + ), + ] diff --git a/authors/apps/articles/models.py b/authors/apps/articles/models.py index cd52b5d..6459434 100644 --- a/authors/apps/articles/models.py +++ b/authors/apps/articles/models.py @@ -32,7 +32,7 @@ class Article(models.Model): Published is like a draft field, helps authors to wor and save them to draft before publishing them """ - published = models.BooleanField(default=False) + published = models.BooleanField(default=True) """ An article can have many tags and the reverse is true @@ -157,3 +157,20 @@ class Readings(models.Model): def __str__(self): return "article_id: {}, author: {}, views: {}".format( self.article, self.author, self.read_count) + + +class ReportArticle(models.Model): + """This class implements a model report articles that violate + terms of agreement + """ + article_id = models.ForeignKey(Article, on_delete=models.CASCADE) + article_slug = models.ForeignKey( + Article, to_field="slug", db_column="slug", related_name='a_slug', on_delete=models.CASCADE, null=True) + reported_by = models.ForeignKey(Profile, on_delete=models.CASCADE) + reason = models.CharField(db_index=True, null=False, max_length=255) + reported_at = models.DateTimeField(auto_now_add=True) + + objects = models.Manager() + + class Meta: + ordering = ['-reported_at'] diff --git a/authors/apps/articles/renderers.py b/authors/apps/articles/renderers.py index 7475162..24391d1 100644 --- a/authors/apps/articles/renderers.py +++ b/authors/apps/articles/renderers.py @@ -38,3 +38,35 @@ def render(self, data, media_type=None, renderer_context=None): }) +class ArticleReportJSONRenderer(JSONRenderer): + charset = 'utf-8' + + def render(self, data, media_type=None, renderer_context=None): + + errors = data.get('errors', None) + + if errors is not None: + + return super(ArticleReportJSONRenderer, self).render(data) + + return json.dumps({ + 'reported': data + }) + + +class ArticleListReportJSONRenderer(JSONRenderer): + charset = 'utf-8' + + def render(self, data, media_type=None, renderer_context=None): + + errors = data.get('errors', None) + + if errors is not None: + + return super(ArticleListReportJSONRenderer, self).render(data) + + return json.dumps({ + 'reported': data + }) + + diff --git a/authors/apps/articles/serializers.py b/authors/apps/articles/serializers.py index 38ccd0f..025a95d 100644 --- a/authors/apps/articles/serializers.py +++ b/authors/apps/articles/serializers.py @@ -11,7 +11,8 @@ ArticleImg, Tag, Favourites, Likes, - Readings + Readings, + ReportArticle ) @@ -29,9 +30,9 @@ class Meta: List all of the fields that could possibly be included in a request or response, this includes fields specified explicitly above. """ - fields = ['title', 'body', 'description', 'tagList', - 'author', 'slug', 'published', 'created_at', 'favourited','favouriteCount', - 'updated_at', 'read_time', 'view_count', 'likes_count', 'read_count' ] + fields = ['id','title', 'body', 'description', 'tagList', + 'author', 'slug', 'published', 'created_at', 'updated_at','favourited','favouriteCount' + ,'read_time', 'view_count', 'likes_count', 'read_count' ] def create(self, validated_data): tags = validated_data.pop('tags', []) @@ -127,4 +128,14 @@ def to_representation(self, instance): return response class Meta: model = Readings - fields = ['read_time', 'article', 'likes_count', 'view_count', 'read_count'] \ No newline at end of file + fields = ['read_time', 'article', 'likes_count', 'view_count', 'read_count'] + +class ReportArticleSerializer(serializers.ModelSerializer): + reported_by = ProfileSerializer(read_only=True) + reported_at = serializers.DateTimeField(read_only=True) + reason = serializers.CharField() + + class Meta: + model = ReportArticle + fields = ['article_id', 'article_slug', + 'reported_by', 'reason', 'reported_at', ] \ No newline at end of file diff --git a/authors/apps/articles/test/base.py b/authors/apps/articles/test/base.py index c9e91ab..c726ac3 100644 --- a/authors/apps/articles/test/base.py +++ b/authors/apps/articles/test/base.py @@ -99,6 +99,20 @@ def setUp(self): } } + self.report_article_data = { + + "report": { + "reason": "article contains porn" + } + } + + self.report_article_data_empty_reason = { + + "report": { + "reason": "" + } + } + self.updated_article = { "article": { diff --git a/authors/apps/articles/test/test_ceate_articles.py b/authors/apps/articles/test/test_ceate_articles.py index f5aeae5..dcb8916 100644 --- a/authors/apps/articles/test/test_ceate_articles.py +++ b/authors/apps/articles/test/test_ceate_articles.py @@ -10,6 +10,10 @@ class TestArticles(BaseTestArticles): def data3_user_jwt(self): return User.objects.create_user(**self.data3['user']).token() + + def super_user_jwt(self): + user = User.objects.create_superuser(**self.data3['user']) + return user.token() def test_create_models_article(self): user = User.objects.create_user( @@ -91,24 +95,21 @@ def test_update_article(self): '/api/articles/'+slug+'/', data=self.updated_article, format='json') self.assertEqual(response.status_code, status.HTTP_201_CREATED) - def test_get_all_articles(self): - self.create_article() - self.create_article() + def test_get_no_existing_published_articles(self): self.client.credentials( HTTP_AUTHORIZATION='Bearer ' + self.login_user()) response = self.client.get( '/api/articles', format='json') - self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) - def test_get_article_tags(self): + def test_get_all_published_articles(self): + self.create_article() + self.create_article() + self.create_article() self.client.credentials( HTTP_AUTHORIZATION='Bearer ' + self.login_user()) - self.client.post( - '/api/articles/', data=self.article, format='json') - slug = self.create_article() response = self.client.get( - '/api/{}/tags/'.format(slug, format='json') - ) + '/api/articles', format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) def test_delete_tag(self): @@ -139,3 +140,172 @@ def test_delete_article_not_author(self): json.loads(res.content)['article']['error'], 'You can only delete your own articles' ) + + def test_report_article(self): + slug = self.create_article() + self.client.credentials( + HTTP_AUTHORIZATION='Bearer ' + self.login_user()) + response = self.client.post( + '/api/articles/{}/report/'.format(slug), + data=self.report_article_data, format='json') + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual( + json.loads(response.content)['reported']['reason'], + 'article contains porn' + ) + + def test_report_article_doesnot_exist(self): + slug = 'fake-slug' + self.client.credentials( + HTTP_AUTHORIZATION='Bearer ' + self.login_user()) + response = self.client.post( + '/api/articles/{}/report/'.format(slug), + data=self.report_article_data, format='json') + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + self.assertEqual( + json.loads(response.content)['errors'], + 'This article doesnot exist' + ) + + def test_report_article_no_data(self): + slug = self.create_article() + self.client.credentials( + HTTP_AUTHORIZATION='Bearer ' + self.login_user()) + response = self.client.post( + '/api/articles/{}/report/'.format(slug), data={}, format='json') + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual( + json.loads(response.content)['errors'], + 'Provide reason for reporting' + ) + + def test_report_article_empty_reason(self): + slug = self.create_article() + self.client.credentials( + HTTP_AUTHORIZATION='Bearer ' + self.login_user()) + response = self.client.post( + '/api/articles/{}/report/'.format(slug), + self.report_article_data_empty_reason, format='json') + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual( + json.loads(response.content)['errors']['reason'], + ['This field may not be blank.'] + ) + + def test_report_article_more_than_5_times(self): + slug = self.create_article() + self.client.credentials( + HTTP_AUTHORIZATION='Bearer ' + self.login_user()) + for article in range(6): + self.client.post( + '/api/articles/{}/report/'.format(slug), + data=self.report_article_data, format='json') + response = self.client.post( + '/api/articles/{}/report/'.format(slug), + data=self.report_article_data, format='json') + self.assertEqual(response.status_code, status.HTTP_409_CONFLICT) + self.assertEqual( + json.loads(response.content)['errors'], + 'This article has been reported more than 5 times' + ) + + def test_fetch_all_reported_articles_non_superuser(self): + self.create_article() + self.create_article() + self.create_article() + self.client.credentials( + HTTP_AUTHORIZATION='Bearer ' + self.login_user()) + response = self.client.get('/api/reported/', format='json') + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual( + json.loads(response.content)['reported']['detail'], + 'You do not have permission to perform this action.' + ) + + def test_fetch_all_reported_articles_superuser(self): + slug1 = self.create_article() + slug2 = self.create_article() + self.client.credentials( + HTTP_AUTHORIZATION='Bearer ' + self.super_user_jwt()) + self.client.post( + '/api/articles/{}/report/'.format(slug1), + data=self.report_article_data, format='json') + self.client.post( + '/api/articles/{}/report/'.format(slug2), + data=self.report_article_data, format='json') + response = self.client.get('/api/reported/', format='json') + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertIn( + slug2, + json.loads(response.content)[ + 'reported']['articles'][0]['article_slug'], + ) + + def test_fetch_all_reported_articles_that_dont_exist(self): + self.client.credentials( + HTTP_AUTHORIZATION='Bearer ' + self.super_user_jwt()) + response = self.client.get('/api/reported/', format='json') + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + self.assertEqual( + json.loads(response.content)['reported']['articles']['message'], + 'There are no reported articles' + ) + + def test_revert_reported_article(self): + slug = self.create_article() + self.client.credentials( + HTTP_AUTHORIZATION='Bearer ' + self.login_user()) + self.client.post( + '/api/articles/{}/report/'.format(slug), format='json') + self.client.post( + '/api/articles/{}/report/'.format(slug), format='json') + self.client.credentials( + HTTP_AUTHORIZATION='Bearer ' + self.super_user_jwt()) + response = self.client.put( + '/api/reported/{}/revert/'.format(slug), format='json') + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual( + response.data['reported']['message'], + 'article restored successully' + ) + + def test_revert_reported_article_doesnot_exist(self): + slug = 'fake_slug' + self.client.credentials( + HTTP_AUTHORIZATION='Bearer ' + self.super_user_jwt()) + response = self.client.put( + '/api/reported/{}/revert/'.format(slug), format='json') + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + + def test_delete_reported_article(self): + slug = self.create_article() + self.client.credentials( + HTTP_AUTHORIZATION='Bearer ' + self.login_user()) + self.client.post( + '/api/articles/{}/report/'.format(slug), format='json') + self.client.post( + '/api/articles/{}/report/'.format(slug), format='json') + self.client.credentials( + HTTP_AUTHORIZATION='Bearer ' + self.super_user_jwt()) + response = self.client.delete( + '/api/reported/{}/delete/'.format(slug), format='json') + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual( + response.data['reported']['message'], + 'article was deleted successully' + ) + + def test_delete_reported_article_doesnot_exist(self): + self.create_article() + slug = 'fakeslug' + self.client.credentials( + HTTP_AUTHORIZATION='Bearer ' + self.super_user_jwt()) + response = self.client.delete( + '/api/reported/{}/delete/'.format(slug), format='json') + self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND) + self.assertEqual( + response.data['reported']['error'], + 'This article doesnot exist' + ) + + diff --git a/authors/apps/articles/urls.py b/authors/apps/articles/urls.py index 5a65fdf..3ec3dfc 100644 --- a/authors/apps/articles/urls.py +++ b/authors/apps/articles/urls.py @@ -9,7 +9,9 @@ ArticleDeleteAPIView, FavouritesView, LikeArticleView, - ReadingView + ReadingView, + ReporteArticleAPIView, + ReportedArticleListAPIView, ) urlpatterns = [ @@ -21,5 +23,13 @@ path('articles/', CreateArticleView.as_view(), name='article-create'), path('/tags/', ArticleTagsAPIView.as_view(), name='article-tags'), path('/tags//', ArticleDeleteAPIView.as_view(), name='delete-tag'), - path('articles//favorite/', FavouritesView.as_view()) -] + path('articles//favorite/', FavouritesView.as_view()), + path('articles//report/', + ReporteArticleAPIView.as_view(), name='report-aticle'), + path('reported//delete/', + ReportedArticleListAPIView.as_view(), name='delete-reported-aticle'), + path('reported//revert/', + ReportedArticleListAPIView.as_view(), name='revert-reported-aticle'), + path('reported/', + ReportedArticleListAPIView.as_view(), name='reported'), +] \ No newline at end of file diff --git a/authors/apps/articles/views.py b/authors/apps/articles/views.py index 5d7db0f..70ebe00 100644 --- a/authors/apps/articles/views.py +++ b/authors/apps/articles/views.py @@ -14,7 +14,8 @@ from rest_framework.permissions import ( AllowAny, IsAuthenticated, - IsAuthenticatedOrReadOnly + IsAuthenticatedOrReadOnly, + IsAdminUser ) from rest_framework.response import Response from rest_framework import exceptions @@ -22,8 +23,22 @@ from authors.settings import RPD from ..authentication.backends import JWTAuthentication from ..authentication.models import User -from .renderers import ArticleJSONRenderer, ListArticlesJSONRenderer -from .models import ArticleImg, Article, Tag, Favourites, Likes, Readings +from .renderers import( + ArticleJSONRenderer, + ListArticlesJSONRenderer, + ArticleJSONRenderer, + ArticleListReportJSONRenderer, + ArticleReportJSONRenderer +) +from .models import( + ArticleImg, + Article, + Tag, + Favourites, + Likes, + Readings, + ReportArticle +) from ..profiles.models import Profile @@ -35,7 +50,8 @@ TagsSerializer, FavouriteSerializer, LikeArticleViewSerializer, - ReadingSerializer + ReadingSerializer, + ReportArticleSerializer ) @@ -119,8 +135,7 @@ def get(self, request, slug): return Response(error, status=status.HTTP_404_NOT_FOUND) serializer = self.serializer_class(article) - article.view_count += 1 - article.save() + image_list = ArticleImg.objects.all().filter( article_id=article.id).values() res = serializer.data @@ -150,6 +165,7 @@ def delete(self, request, slug): {"error": "You can only delete your own articles"}, status=status.HTTP_401_UNAUTHORIZED ) + article.delete() except Article.DoesNotExist: error = {"error": "This article doesnot exist"} @@ -173,15 +189,6 @@ def put(self, request, slug): user_info = JWTAuthentication().authenticate(request) current_user = user_info[0] profile = Profile.objects.get(user__id=current_user.id) - - """ - estimates the time an article should take to be read - """ - article_body = article["body"] - results = readtime.of_text(article_body) - read_time = results.minutes - article['read_time'] = read_time - image_data = article['images'] for image in image_data: image_obj = ArticleImg.objects.filter( @@ -205,12 +212,6 @@ def put(self, request, slug): article_ob = Article.objects.get(slug=slug) - """ - saves the readtime value to the database - """ - article_ob.read_time = read_time - article_ob.save() - image_list = ArticleImg.objects.all().filter( article_id=article_ob.id).values() res = serializer.data @@ -233,7 +234,7 @@ def get(self, request): """ This class method is used retrieve articles """ - articles = Article.objects.all() + articles = Article.objects.filter(published=True) article_list = [] for article in list(articles): images = ArticleImg.objects.filter( @@ -245,9 +246,11 @@ def get(self, request): images_list.append(image) article['images'] = images_list article_list.append(article) + if len(article_list) == 0: + data = {'message': 'There are no articles articles'} + return Response({"articles": data}, status=status.HTTP_404_NOT_FOUND) return Response(article_list, status=status.HTTP_200_OK) - class ArticleTagsAPIView(GenericAPIView): queryset = Tag.objects.all() permission_classes = (IsAuthenticatedOrReadOnly,) @@ -490,6 +493,99 @@ def post(self, request, slug, count): else: serializer = self.serializer_class(reader.first()) return Response(serializer.data, status=status.HTTP_200_OK) + +class ReporteArticleAPIView(GenericAPIView): + permission_classes = (IsAuthenticated,) + renderer_classes = (ArticleReportJSONRenderer,) + serializer_class = ReportArticleSerializer + + def post(self, request, *args, **kwargs): + + user_data = JWTAuthentication().authenticate(request) + profile = Profile.objects.get(user__id=user_data[0].id) + slug = kwargs['slug'] + report = request.data.get('report', {}) + if report == {}: + return Response( + {"errors": "Provide reason for reporting"}, + status=status.HTTP_400_BAD_REQUEST + ) + try: + article_ob = Article.objects.get( + slug=slug + ) + except Article.DoesNotExist: + return Response( + {"errors": "This article doesnot exist"}, + status=status.HTTP_404_NOT_FOUND + ) + reported_articles = ReportArticle.objects.filter( + article_id=article_ob.id) + if len(list(reported_articles)) >= 5: + article_ob.published = False + article_ob.save() + return Response( + data={ + "errors": "This article has been reported more than 5 times" + }, + status=status.HTTP_409_CONFLICT + ) + + serializer = self.serializer_class(data=report, partial=True) + serializer.is_valid(raise_exception=True) + serializer.save( + article_id=article_ob, + article_slug=article_ob, + reported_by=profile + ) + return Response(serializer.data, status=status.HTTP_200_OK) + +class ReportedArticleListAPIView(GenericAPIView): + serializer_class = ReportArticleSerializer + renderer_classes = (ArticleListReportJSONRenderer,) + permission_classes = (IsAuthenticated, IsAdminUser) + + def get(self, request): + queryset = ReportArticle.objects.filter() + serializer = self.serializer_class(queryset, many=True) + data = serializer.data + if len(data) == 0: + data = {'message': 'There are no reported articles'} + return Response({"articles": data}, + status=status.HTTP_404_NOT_FOUND) + return Response({"articles": data}, status=status.HTTP_200_OK) + + def put(self, request, slug): + """Revert mistakenly reported articles + """ + try: + article = Article.objects.get(slug=slug) + article.published = True + article.save() + except Article.DoesNotExist: + error = {"error": "This article doesnot exist"} + return Response(error, status=status.HTTP_404_NOT_FOUND) + + reported_article = ReportArticle.objects.filter( + article_id=article.id) + reported_article.delete() + + data = {"message": "article restored successully"} + return Response({"reported": data}, status=status.HTTP_200_OK) + + def delete(self, request, slug): + """Permernebtly delete article from database which + has been verified to violate terms + """ + try: + article = Article.objects.get(slug=slug) + except Article.DoesNotExist: + error = {"error": "This article doesnot exist"} + return Response({"reported": error}, + status=status.HTTP_404_NOT_FOUND) + article.delete() + data = {"message": "article was deleted successully"} + return Response({"reported": data}, status=status.HTTP_200_OK) diff --git a/authors/apps/authentication/migrations/0001_initial.py b/authors/apps/authentication/migrations/0001_initial.py new file mode 100644 index 0000000..975835c --- /dev/null +++ b/authors/apps/authentication/migrations/0001_initial.py @@ -0,0 +1,37 @@ +# Generated by Django 2.1.3 on 2018-12-20 13:18 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0009_alter_user_last_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='User', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('username', models.CharField(db_index=True, max_length=255, unique=True)), + ('email', models.EmailField(db_index=True, max_length=254, unique=True)), + ('is_active', models.BooleanField(default=True)), + ('social_id', models.CharField(db_index=True, max_length=255, null=True)), + ('is_verified', models.BooleanField(default=False)), + ('is_staff', models.BooleanField(default=False)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/authors/apps/authentication/serializers.py b/authors/apps/authentication/serializers.py index 54b1b4b..5abb75e 100644 --- a/authors/apps/authentication/serializers.py +++ b/authors/apps/authentication/serializers.py @@ -127,10 +127,16 @@ def validate(self, data): raise serializers.ValidationError( 'A user with this email and password was not found.' ) + + if user.is_superuser: + user.is_verified = True + user.save() + if user.is_verified == False: raise serializers.ValidationError( 'Your email is not verified, Please check your email for a verification link' ) + # Django provides a flag on our `User` model called `is_active`. The # purpose of this flag to tell us whether the user has been banned diff --git a/authors/apps/profiles/migrations/0001_initial.py b/authors/apps/profiles/migrations/0001_initial.py new file mode 100644 index 0000000..65fcc0b --- /dev/null +++ b/authors/apps/profiles/migrations/0001_initial.py @@ -0,0 +1,34 @@ +# Generated by Django 2.1.3 on 2018-12-20 13:18 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Follow', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('followed', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='followed_user_id', to=settings.AUTH_USER_MODEL)), + ('follower', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='follower_user_id', to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='Profile', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('bio', models.TextField(blank=True)), + ('image', models.URLField(blank=True)), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/authors/apps/profiles/serializers.py b/authors/apps/profiles/serializers.py index 7e5aabf..c503855 100644 --- a/authors/apps/profiles/serializers.py +++ b/authors/apps/profiles/serializers.py @@ -47,3 +47,6 @@ class FollowerSerializer(serializers.ModelSerializer): class Meta: model = Follow fields = ['followed'] + + + \ No newline at end of file diff --git a/authors/apps/profiles/test/test_create_profile.py b/authors/apps/profiles/test/test_create_profile.py index 6ce767d..f965929 100644 --- a/authors/apps/profiles/test/test_create_profile.py +++ b/authors/apps/profiles/test/test_create_profile.py @@ -19,6 +19,20 @@ def setUp(self): } } + self.user1 = { + 'user': { + 'email': "kica@gmail.com", + 'username': "kica", + 'password': 'Sokosok1!' + } + } + self.user2 = { + 'user': { + 'email': "ntale@gmail.com", + 'username': "shadik", + 'password': 'Sokosok1!' + } + } def verify_account(self, token, uidb64): request = APIRequestFactory().get( reverse( @@ -83,3 +97,30 @@ def test_update_profile(self): json.loads(response.content)['profile']['bio'], "I love andela" ) + + def create_super_user(self): + admin = User.objects.create_superuser( + 'soko', 'soko@gmail.com', 'Sokosok1!') + response = self.client.post( + '/api/users/login/', self.user, format='json') + token = response.data['token'] + return token + + def test_get_list_of_profiles(self): + self.client.credentials( + HTTP_AUTHORIZATION='Bearer ' + self.create_super_user()) + self.client.post('/api/users/', self.user1, format='json') + self.client.post('/api/users/', self.user2, format='json') + response = self.client.get('/api/profiles/') + profiles = json.loads(response.content) + self.assertEqual(len(profiles), 3) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + def test_get_list_of_profiles_by_non_admin(self): + self.client.credentials( + HTTP_AUTHORIZATION='Bearer ' + self.create_testing_user()) + self.client.post('/api/users/', self.user1, format='json') + self.client.post('/api/users/', self.user2, format='json') + response = self.client.get('/api/profiles/') + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + diff --git a/authors/apps/profiles/urls.py b/authors/apps/profiles/urls.py index e820892..ef6279d 100644 --- a/authors/apps/profiles/urls.py +++ b/authors/apps/profiles/urls.py @@ -1,6 +1,9 @@ from django.urls import include, path from django.conf.urls import url -from .views import ProfileRetrieveView, FollowAPIView, FollowingAPIView, FollowersAPIView +from .views import (ProfileRetrieveView, FollowAPIView, +FollowingAPIView, +FollowersAPIView, +ListProfilesView) urlpatterns = [ path('profiles/following', FollowingAPIView.as_view()), @@ -8,4 +11,5 @@ url('^profiles/(?P[-\w]+)$', ProfileRetrieveView.as_view(), name='profiles'), path('profiles//follow', FollowAPIView.as_view()), + path('profiles/', ListProfilesView.as_view()), ] diff --git a/authors/apps/profiles/views.py b/authors/apps/profiles/views.py index d4db788..3bd1f7d 100644 --- a/authors/apps/profiles/views.py +++ b/authors/apps/profiles/views.py @@ -8,10 +8,14 @@ from rest_framework import status from rest_framework.generics import RetrieveAPIView, GenericAPIView -from rest_framework.permissions import AllowAny, IsAuthenticated +from rest_framework.permissions import AllowAny, IsAuthenticated, IsAdminUser from rest_framework.response import Response -from .serializers import ProfileSerializer, FollowSerializer, FollowingSerializer, FollowerSerializer +from .serializers import (ProfileSerializer, +FollowSerializer, +FollowingSerializer, +FollowerSerializer, +) class ProfileRetrieveView(RetrieveAPIView): @@ -33,7 +37,6 @@ def retrieve(self, request, *args, **kwargs): return Response(serializer.data, status=status.HTTP_200_OK) - class FollowAPIView(GenericAPIView): """ api view handles following/unfollowing a user @@ -180,3 +183,20 @@ def get(self, request, *args, **kwargs): res = {"followers": profiles} return Response(res, status=status.HTTP_200_OK) + + +class ListProfilesView(RetrieveAPIView): + """ + Lists the profiles of all authors in the system. + """ + permission_classes = (IsAdminUser,) + serializer_class = ProfileSerializer + + def retrieve(self, request): + + profile = Profile.objects.all() + serializer = self.serializer_class(profile, many=True) + + return Response(serializer.data, status=status.HTTP_200_OK) + +