diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..378d477 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,67 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ develop ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ develop ] + schedule: + - cron: '35 9 * * 6' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + language: [ 'javascript', 'python' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # â„šī¸ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # âœī¸ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/ossar-analysis.yml b/.github/workflows/ossar-analysis.yml new file mode 100644 index 0000000..513afd6 --- /dev/null +++ b/.github/workflows/ossar-analysis.yml @@ -0,0 +1,44 @@ +# This workflow integrates a collection of open source static analysis tools +# with GitHub code scanning. For documentation, or to provide feedback, visit +# https://github.com/github/ossar-action +name: OSSAR + +on: + push: + branches: [ develop ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ develop ] + schedule: + - cron: '26 13 * * 4' + +jobs: + OSSAR-Scan: + # OSSAR runs on windows-latest. + # ubuntu-latest and macos-latest support coming soon + runs-on: windows-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Ensure a compatible version of dotnet is installed. + # The [Microsoft Security Code Analysis CLI](https://aka.ms/mscadocs) is built with dotnet v3.1.201. + # A version greater than or equal to v3.1.201 of dotnet must be installed on the agent in order to run this action. + # GitHub hosted runners already have a compatible version of dotnet installed and this step may be skipped. + # For self-hosted runners, ensure dotnet version 3.1.201 or later is installed by including this action: + # - name: Install .NET + # uses: actions/setup-dotnet@v1 + # with: + # dotnet-version: '3.1.x' + + # Run open source static analysis tools + - name: Run OSSAR + uses: github/ossar-action@v1 + id: ossar + + # Upload results to the Security tab + - name: Upload OSSAR results + uses: github/codeql-action/upload-sarif@v1 + with: + sarif_file: ${{ steps.ossar.outputs.sarifFile }} diff --git a/.gitignore b/.gitignore index 620be43..1cfc82f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,36 +1,28 @@ -env -dump -config-bos-mint.yaml - -config-bos-mint.yaml - +.idea/ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] -*$py.class # C extensions *.so # Distribution / packaging .Python +env/ build/ develop-eggs/ dist/ downloads/ eggs/ -.eggs/ lib/ lib64/ parts/ sdist/ var/ -wheels/ -share/python-wheels/ *.egg-info/ .installed.cfg *.egg -MANIFEST +*.eggs # PyInstaller # Usually these files are written by a python script from a template @@ -45,17 +37,10 @@ pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ -.nox/ .coverage -.coverage.* .cache nosetests.xml coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ # Translations *.mo @@ -63,82 +48,15 @@ cover/ # Django stuff: *.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy # Sphinx documentation docs/_build/ +docs/html # PyBuilder -.pybuilder/ target/ -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ +# Vim temp files +*.swp -# Cython debug symbols -cython_debug/ +.ropeproject/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c210439..0e538d3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,6 +13,7 @@ gemnasium-python-dependency_scanning: stages: - test + - deploy test: stage: test @@ -20,3 +21,12 @@ test: - apt-get update -qy - apt-get install -y python3-dev python3-pip build-essential sqlite3 - pip3 install -r requirements.txt + +deployToDev: + stage: deploy + script: + - deployToDev + tags: + - cp1 + only: + - develop \ No newline at end of file diff --git a/README.md b/README.md index 2b1b2f4..59edcbe 100644 --- a/README.md +++ b/README.md @@ -2,22 +2,36 @@ The project is a web based implementation of couch potato. +## Requirements +- Python 3 +- Virtualenv +- GCC +- Git +- MongoDB +- SQLite + +### Ubuntu 18+ +```bash +sudo apt-get update +sudo apt-get install python3 python3-venv python3-dev build-essential git mongodb libmysqlclient-dev -y +``` + ## Installation -```bash +```bash cd python-cp-gui python3 -m venv env source env/bin/activate pip3 install -r requirements.txt +# Configure config-bos-mint.yaml +cd couchpotato +cp example-config-bos-mint.yaml config-bos-mint.yaml ``` - - ### First Run -Modify config-bos-mint.yaml - ```bash +cd python-cp-gui source env/bin/activate cd couchpotato/scripts/ ./install.sh @@ -26,7 +40,9 @@ cd couchpotato/scripts/ This operation will clear all the existing users ## Usage + ```bash +cd python-cp-gui source env/bin/activate cd couchpotato python3 manage.py runserver 0.0.0.0:9010 @@ -41,4 +57,15 @@ openAPI 2.0 documentation is available at /swagger and /redoc ## Uninsallation Delete the python-cp-gui folder +## TLS +To run development cerver with TLS +python3 manage.py runsslserver 0.0.0.0:9020 + +To generate self signed certificates +sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt + +To run with certificates +python3 manage.py runsslserver 0.0.0.0:9020 --certificate tls.crt --key tls.key + + diff --git a/__version__ b/__version__ index 0ea3a94..0d91a54 100644 --- a/__version__ +++ b/__version__ @@ -1 +1 @@ -0.2.0 +0.3.0 diff --git a/couchpotato/calender/__init__.py b/couchpotato/calender/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/couchpotato/calender/admin.py b/couchpotato/calender/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/couchpotato/calender/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/couchpotato/calender/apps.py b/couchpotato/calender/apps.py new file mode 100644 index 0000000..811332c --- /dev/null +++ b/couchpotato/calender/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class CalenderConfig(AppConfig): + name = 'calender' diff --git a/couchpotato/calender/migrations/__init__.py b/couchpotato/calender/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/couchpotato/calender/models.py b/couchpotato/calender/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/couchpotato/calender/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/couchpotato/calender/templates/calender.html b/couchpotato/calender/templates/calender.html new file mode 100644 index 0000000..43c3aea --- /dev/null +++ b/couchpotato/calender/templates/calender.html @@ -0,0 +1,241 @@ +{% load static %} + + + + + + + + + + + + + + + + + + + + + + + + + + + {% include "navbar.html" %} + + +
+ +
loading...
+
+ +
+ Return to Home + Update +
+ + +
+ + + + + + diff --git a/couchpotato/game/tests.py b/couchpotato/calender/tests.py similarity index 100% rename from couchpotato/game/tests.py rename to couchpotato/calender/tests.py diff --git a/couchpotato/calender/urls.py b/couchpotato/calender/urls.py new file mode 100644 index 0000000..272ca0b --- /dev/null +++ b/couchpotato/calender/urls.py @@ -0,0 +1,16 @@ + +from django.urls import path ,re_path +from . import views +from django.conf.urls.static import static +from django.contrib.staticfiles.urls import staticfiles_urlpatterns +from django.views.static import serve +from django.urls import path, include + + +urlpatterns = [ + + path('',views.index,name= 'calender.html'), + +] + +urlpatterns += staticfiles_urlpatterns() \ No newline at end of file diff --git a/couchpotato/calender/views.py b/couchpotato/calender/views.py new file mode 100644 index 0000000..985a86b --- /dev/null +++ b/couchpotato/calender/views.py @@ -0,0 +1,19 @@ +from django.shortcuts import render + +# Create your views here. +from home.utilities import index_page_permitted + + +def index(request): + ''' + Decription: Render function to display calender + ''' + + try: + if index_page_permitted(request): + return render(request, "calender.html") + else: + return render(request, 'login.html') + except: + return render(request, '404.html') + \ No newline at end of file diff --git a/couchpotato/couchpotato/settings.py b/couchpotato/couchpotato/settings.py index cdef0d8..6cbf247 100644 --- a/couchpotato/couchpotato/settings.py +++ b/couchpotato/couchpotato/settings.py @@ -23,7 +23,8 @@ SECRET_KEY = '!fwkygc(zdgod8v934b9q(grdp7#(kd1vav4h)sdi6y_6p!oq6' # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +DEBUG = False +BOOL_SSLSERVER = True ALLOWED_HOSTS = ['*'] @@ -33,14 +34,17 @@ INSTALLED_APPS = [ 'home', 'game', + 'calender', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', - 'drf_yasg', - 'rest_framework', + 'drf_yasg', + 'rest_framework', + 'sslserver', + #'rest_framework_swagger', ] @@ -135,7 +139,7 @@ STATIC_URL = '/static/' -if DEBUG: +if DEBUG or BOOL_SSLSERVER: STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static') ] diff --git a/couchpotato/couchpotato/urls.py b/couchpotato/couchpotato/urls.py index d61d32e..ccc13be 100644 --- a/couchpotato/couchpotato/urls.py +++ b/couchpotato/couchpotato/urls.py @@ -44,7 +44,10 @@ urlpatterns = [ path('', include('home.urls')), path('openapi/' , include('game.urls')), + path('calendar/', include('calender.urls')), path('admin/', admin.site.urls), + + re_path(r'^swagger(?P\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'), path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), diff --git a/couchpotato/cp_local.py b/couchpotato/cp_local.py deleted file mode 120000 index e848dd4..0000000 --- a/couchpotato/cp_local.py +++ /dev/null @@ -1 +0,0 @@ -../feed/cp_local.py \ No newline at end of file diff --git a/couchpotato/cp_local.py b/couchpotato/cp_local.py new file mode 100644 index 0000000..6ce5489 --- /dev/null +++ b/couchpotato/cp_local.py @@ -0,0 +1,800 @@ + +from bos_incidents import factory, exceptions +import _thread +import time +import numpy as np +import pandas as pd +from bos_mint.node import Node +from bookiesports.normalize import IncidentsNormalizer +from bookiesports import BookieSports +from bos_incidents.format import string_to_incident, incident_to_string +from bos_incidents.datestring import date_to_string, string_to_date +from datetime import datetime, timezone +import requests +import yaml +import logging + +with open("config-bos-mint.yaml", "r") as f: + config = yaml.safe_load(f) +chainName = config["connection"]["use"] +bosApis = config["bosApis"] +potatoNames = config["potatoNames"] + +# Create and configure logger +# logging.basicConfig(filename="za.log", +# format='%(asctime)s %(message)s', +# filemode='a') +# Creating an object +logger = logging.getLogger() + +# Setting the threshold of logger to DEBUG +logger.setLevel(logging.INFO) + +node = Node() +# node.unlock("peerplays**") +# node.unlock(config["password"]) +ppy = node.get_node() +rpc = ppy.rpc + +INCIDENT_CALLS = [ + "create", + "in_progress", + "finish", + "result", + "canceled", + "dynamic_bmgs", +] + +STATUSES = ["upcoming", "in_progress", "finished"] + +# normalizer = IncidentsNormalizer(chain="elizabeth") +normalizer = IncidentsNormalizer(chain=chainName) +normalize = normalizer.normalize + +# Incident Storage +storage = factory.get_incident_storage() + + +def substitution(teams, scheme): + class Teams: + home = " ".join([x for x in teams[0].split(" ")]) + away = " ".join([x for x in teams[1].split(" ")]) + + ret = dict() + for lang, name in scheme.items(): + ret[lang] = name.format(teams=Teams) + ret = ret["en"] + return ret + + +class Cp(): + + def __init__(self): + self.maxOpenProposals = 2 + self.delayBetweenBosPushes = 1 # in seconds + self.bookiesports = BookieSports(chainName) + pass + + def GetKey(self, keys): + keys = list(keys) + k = 0 + for key in keys: + print(k, key) + k = k + 1 + index = input("Enter index of key: ") + index = int(index) + return keys[index] + + def GetKeyParticipant(self, keys, participantDisplays): + keys = list(keys) + k = 0 + for key in keys: + # print(k, participantDisplays[k]) + print(k, key) + k = k + 1 + index = input("Enter index of key: ") + index = int(index) + return keys[index] + + def GetSportsList(self): + return list(self.bookiesports.keys()) + + def GetEventGroupsList(self, sport): + eventGroupsList = self.bookiesports[sport]["eventgroups"].keys() + eventGroupsList = list(eventGroupsList) + return eventGroupsList + + def GetParticipants(self, sport, participantKey): + participants = self.bookiesports[sport]["participants"][ + participantKey]["participants"] + particpantIdentifiers = [] + participantDisplays = [] + for participant in participants: + # particpantIdentifiers.append(participant["aliases"][0]) + participantDisplays.append(participant.values()) + particpantIdentifiers.append(participant["identifier"]) + # particpantIdentifiers.append(participant["name"]["en"]) + return particpantIdentifiers, participantDisplays + + def GetForCreate(self, sport=None, eventGroup=None): + if isinstance(sport, type(None)): + self._sportsList = self.GetSportsList() + return self._sportsList + if isinstance(eventGroup, type(None)): + self._eventGroupsList = self.GetEventGroupsList(sport) + return self._eventGroupsList +# self._eventGroupIdentifier = self.bookiesports[sport][ +# "eventgroups"][eventGroup]["identifier"] + self._participantKey = self.bookiesports[sport]["eventgroups"][ + eventGroup]["participants"] + self._participants, participantDisplays = self.GetParticipants( + sport, self._participantKey) + return self._participants + + def CreateForApi(self, sport, eventGroup, home, away, startTime): + incident = dict() + incident["call"] = INCIDENT_CALLS[0] + + incident["id"] = dict() + incident["id"]["sport"] = sport + eventGroupIdentifier = self.bookiesports[sport][ + "eventgroups"][eventGroup]["identifier"] + incident["id"]["event_group_name"] = eventGroupIdentifier + # incident["id"]["event_group_name"] = self._eventGroup + startTime = date_to_string(startTime) + incident["id"]["start_time"] = startTime + incident["arguments"] = {"whistle_start_time": startTime} + incident["id"]["home"] = home + incident["id"]["away"] = away + incident["timestamp"] = date_to_string(datetime.now(tz=timezone.utc)) + incident["arguments"]["season"] = "" + + rs = [] + for potatoName in potatoNames: + r = self.Push2bos(incident, potatoName) + rs.append(r) + return incident, rs + + def CreateForApiWithPotato( + self, sport, eventGroup, home, away, startTime, potato): + incident = dict() + incident["call"] = INCIDENT_CALLS[0] + + incident["id"] = dict() + incident["id"]["sport"] = sport + eventGroupIdentifier = self.bookiesports[sport][ + "eventgroups"][eventGroup]["identifier"] + incident["id"]["event_group_name"] = eventGroupIdentifier + # incident["id"]["event_group_name"] = self._eventGroup + startTime = date_to_string(startTime) + incident["id"]["start_time"] = startTime + incident["arguments"] = {"whistle_start_time": startTime} + incident["id"]["home"] = home + incident["id"]["away"] = away + incident["timestamp"] = date_to_string(datetime.now(tz=timezone.utc)) + incident["arguments"]["season"] = "" + + self.Push2bos(incident, potato) + return incident + + def CliManufactureCreateIncident(self): + self._call = INCIDENT_CALLS[0] + self._sportsList = self.GetSportsList() + print("") + print("Select Sport") + self._sport = self.GetKey(self._sportsList) + # self._sport = self.bookiesports[self._sport]["aliases"][0] + self._eventGroupsList = self.GetEventGroupsList(self._sport) + print("") + print("Select Event Group") + self._eventGroup = self.GetKey(self._eventGroupsList) + self._eventGroupIdentifier = self.bookiesports[self._sport][ + "eventgroups"][self._eventGroup]["identifier"] + # self._eventGroupIdentifier = self.bookiesports[self._sport][ + # "eventgroups"][self._eventGroup]["aliases"][0] + self._participantKey = self.bookiesports[self._sport]["eventgroups"][ + self._eventGroup]["participants"] + self._participants, participantDisplays = self.GetParticipants( + self._sport, self._participantKey) + print("") + print("Select Home Team") + self._home = self.GetKeyParticipant( + self._participants, participantDisplays) + print("") + print("Select Away Team") + self._away = self.GetKeyParticipant( + self._participants, participantDisplays) + + incident = dict() + incident["call"] = self._call + + # incident["arguments"] = { + # "whistle_start_time": "2020-08-25T22:22:45.00Z"} + incident["id"] = dict() + incident["id"]["sport"] = self._sport + incident["id"]["event_group_name"] = self._eventGroupIdentifier + # incident["id"]["event_group_name"] = self._eventGroup + print("") + startTime = input( + "Enter Start Time in the format 2020-08-25T22:00:00Z :") + startTime = date_to_string(startTime) + incident["id"]["start_time"] = startTime + incident["arguments"] = {"whistle_start_time": startTime} + # incident["id"]["start_time"] = "2020-08-25T22:00:00Z" + incident["id"]["home"] = self._home + incident["id"]["away"] = self._away + incident["timestamp"] = date_to_string(datetime.now(tz=timezone.utc)) + incident["arguments"]["season"] = "" + + # string = incident_to_string(incident) + + return incident + + def EventsAllSorted(self): + print('Fetching all active events, wait a few seconds') + eventsAll = node.getEvents("all") + eventsAll = pd.DataFrame(eventsAll) + if len(eventsAll) == 0: + return None + eventsAll = eventsAll.sort_values("start_time") + return eventsAll + + def EventsAllSortedForApi(self): + print('Fetching all active events, wait a few seconds') + try: + eventsAllRaw = node.getEvents("all") + self.eventsAllRaw = eventsAllRaw + except Exception as e: + logger.info(e) + eventsAllRaw = self.eventsAllRaw + eventsAll = pd.DataFrame(eventsAllRaw) + if len(eventsAll) == 0: + return None + eventsAll = eventsAll.sort_values("start_time") + eventsAllList = [] + for k in range(len(eventsAll)): + eventsAllList.append(dict(eventsAll.iloc[k])) + eventsAllList = self.EventsAllWithEventGroupName(eventsAllList) + return eventsAllList + + def EventsAllWithEventGroupName(self, eventsAll): + for event in eventsAll: + event_group_id = event["event_group_id"] + # event["event_group_name"] = rpc.get_object( + # event_group_id)["name"][1][1] + eventGroup = rpc.get_object(event_group_id) + + event["event_group_name"] = dict(eventGroup["name"])["identifier"] + # event["event_group_name"] = eventGroup["name"][1][1] + sport = rpc.get_object(eventGroup["sport_id"]) + sport = dict(sport["name"])["identifier"] + event["sport"] = sport + # sport = normalizer._get_sport_identifier(sport, True) + return eventsAll + + def Event2Update(self): + eventsAll = self.EventsAllSorted() + if isinstance(eventsAll, type(None)): + return None + self._eventsAll = eventsAll + for k in range(len(eventsAll)): + event = eventsAll.iloc[k] + print("") + print(event) + eventGroup = node.getEventGroup(event["event_group_id"]) + print(eventGroup["name"]) + sport = node.getSport(eventGroup["sport_id"]) + print(sport) + choice = input( + "'U'pdate the event/'S'kip to the next event, u/s : ") + if choice == "u": + return event + else: + k = k + 1 + return None + + def HomeAway(self, homeAway): + try: + home, away = homeAway.split(" @ ") + except ValueError: + home, away = homeAway.split(" v ") + return home, away + + def EventGroupAlias(self, sport, eventGroup): + bookieEventGroups = self.bookiesports[sport]["eventgroups"] + keys = list(bookieEventGroups.keys()) + for key in keys: + if eventGroup == bookieEventGroups[key]["identifier"]: + return bookieEventGroups[key]["aliases"][0] + print("eventGroup Identifier NOT found: ", sport, eventGroup) + + def EventScheme(self, sport, eventGroup): + sports = self.bookiesports[sport] + eventGroups = sports["eventgroups"] + for eg in eventGroups: + if eventGroups[eg]["identifier"] == eventGroup: + eventScheme = eventGroups[eg] + eventScheme = eventScheme["eventscheme"]["name"] + return eventScheme + + def UpdateForApi(self, event, call, homeScore=None, awayScore=None): + self._event = event + self._call = call + incident = dict() + incident["call"] = self._call + + startTime = event["start_time"] + "Z" + self._starttime = startTime + incident["id"] = dict() + eventGroup = rpc.get_object(event["event_group_id"]) + + sport = rpc.get_object(eventGroup["sport_id"]) + + eventGroup = dict(eventGroup["name"])["identifier"] + sport = dict(sport["name"])["identifier"] + sport = normalizer._get_sport_identifier(sport, True) + self._sport = sport + sportAlias = self.bookiesports[sport]["aliases"][0] + + print(sport, eventGroup, startTime) + + eventGroup = normalizer._get_eventgroup_identifier( + sport, + eventGroup, + startTime, + True) + + self._eventGroup = eventGroup + # eventGroupAlias = self.EventGroupAlias(sport, eventGroup) + # eventGroupAlias = self.bookiesports[sport]["eventgroups"][ + # eventGroup]["aliases"][0] + + homeAway = event["name"][0][1] + self._homeAway = homeAway + home, away = self.HomeAway(homeAway) + eventScheme = self.EventScheme(sport, eventGroup) + homeAway = substitution([home, away], eventScheme) + home, away = self.HomeAway(homeAway) + + homeAlias = normalizer._get_participant_identifier( + sport, + eventGroup, + home, + True) + + awayAlias = normalizer._get_participant_identifier( + sport, + eventGroup, + away, + True) + + # incident["id"]["event_group_name"] = eventGroupAlias + incident["id"]["event_group_name"] = eventGroup + + incident["id"]["sport"] = sportAlias + + incident["id"]["start_time"] = startTime + incident["arguments"] = {"whistle_start_time": startTime} + # incident["id"]["start_time"] = "2020-08-25T22:00:00Z" + + incident["id"]["home"] = homeAlias + incident["id"]["away"] = awayAlias + incident["timestamp"] = date_to_string(datetime.now(tz=timezone.utc)) + incident["arguments"]["season"] = event["season"][0][1] + + if self._call == "result": + incident["arguments"]["home_score"] = homeScore + incident["arguments"]["away_score"] = awayScore + + self._incident = incident + # string = incident_to_string(incident) + + rs = [] + for potatoName in potatoNames: + r = self.Push2bos(incident, potatoName) + rs.append(r) + return incident, rs + + def UpdateForApiWithPotato( + self, event, call, potato, homeScore=None, awayScore=None): + self._event = event + self._call = call + incident = dict() + incident["call"] = self._call + + startTime = event["start_time"] + "Z" + self._starttime = startTime + incident["id"] = dict() + eventGroup = rpc.get_object(event["event_group_id"]) + + sport = rpc.get_object(eventGroup["sport_id"]) + + eventGroup = dict(eventGroup["name"])["identifier"] + sport = dict(sport["name"])["identifier"] + sport = normalizer._get_sport_identifier(sport, True) + self._sport = sport + sportAlias = self.bookiesports[sport]["aliases"][0] + + eventGroup = normalizer._get_eventgroup_identifier( + sport, + eventGroup, + startTime, + True) + + self._eventGroup = eventGroup + # eventGroupAlias = self.EventGroupAlias(sport, eventGroup) + # eventGroupAlias = self.bookiesports[sport]["eventgroups"][ + # eventGroup]["aliases"][0] + + homeAway = event["name"][0][1] + self._homeAway = homeAway + home, away = self.HomeAway(homeAway) + eventScheme = self.EventScheme(sport, eventGroup) + homeAway = substitution([home, away], eventScheme) + home, away = self.HomeAway(homeAway) + + homeAlias = normalizer._get_participant_identifier( + sport, + eventGroup, + home, + True) + + awayAlias = normalizer._get_participant_identifier( + sport, + eventGroup, + away, + True) + + # incident["id"]["event_group_name"] = eventGroupAlias + incident["id"]["event_group_name"] = eventGroup + + incident["id"]["sport"] = sportAlias + + incident["id"]["start_time"] = startTime + incident["arguments"] = {"whistle_start_time": startTime} + # incident["id"]["start_time"] = "2020-08-25T22:00:00Z" + + incident["id"]["home"] = homeAlias + incident["id"]["away"] = awayAlias + incident["timestamp"] = date_to_string(datetime.now(tz=timezone.utc)) + incident["arguments"]["season"] = event["season"][0][1] + + if self._call == "result": + incident["arguments"]["home_score"] = homeScore + incident["arguments"]["away_score"] = awayScore + + self._incident = incident + # string = incident_to_string(incident) + + self.Push2bos(incident, potato) + return incident + + def CliUpdate(self): + event = self.Event2Update() + if isinstance(event, type(None)): + return None + self._event = event + print("") + print("Select Call") + self._call = self.GetKey(INCIDENT_CALLS[1:-1]) + incident = dict() + incident["call"] = self._call + + # incident["arguments"] = { + # "whistle_start_time": "2020-08-25T22:22:45.00Z"} + startTime = event["start_time"] + "Z" + self._starttime = startTime + incident["id"] = dict() + eventGroup = rpc.get_object(event["event_group_id"]) + + sport = rpc.get_object(eventGroup["sport_id"]) + + # eventGroup = dict(eventGroup["name"])["identifier"] + eventGroup = dict(eventGroup["name"])["identifier"] + # sport = dict(sport["name"])["identifier"] + sport = dict(sport["name"])["identifier"] + sport = normalizer._get_sport_identifier(sport, True) + self._sport = sport + sportAlias = self.bookiesports[sport]["aliases"][0] + + eventGroup = normalizer._get_eventgroup_identifier( + sport, + eventGroup, + startTime, + True) + + self._eventGroup = eventGroup + # eventGroupAlias = self.EventGroupAlias(sport, eventGroup) + # eventGroupAlias = self.bookiesports[sport]["eventgroups"][ + # eventGroup]["aliases"][0] + + homeAway = event["name"][0][1] + self._homeAway = homeAway + home, away = self.HomeAway(homeAway) + eventScheme = self.EventScheme(sport, eventGroup) + homeAway = substitution([home, away], eventScheme) + home, away = self.HomeAway(homeAway) + + homeAlias = normalizer._get_participant_identifier( + sport, + eventGroup, + home, + True) + + awayAlias = normalizer._get_participant_identifier( + sport, + eventGroup, + away, + True) + + # incident["id"]["event_group_name"] = eventGroupAlias + incident["id"]["event_group_name"] = eventGroup + + incident["id"]["sport"] = sportAlias + + incident["id"]["start_time"] = startTime + incident["arguments"] = {"whistle_start_time": startTime} + # incident["id"]["start_time"] = "2020-08-25T22:00:00Z" + + incident["id"]["home"] = homeAlias + incident["id"]["away"] = awayAlias + incident["timestamp"] = date_to_string(datetime.now(tz=timezone.utc)) + incident["arguments"]["season"] = event["season"][0][1] + + if self._call == "result": + print("") + homeScore = input("Enter Home " + homeAlias + " Score: ") + print("") + awayScore = input("Enter Away " + awayAlias + " Score: ") + incident["arguments"]["home_score"] = homeScore + incident["arguments"]["away_score"] = awayScore + + self._incident = incident + # string = incident_to_string(incident) + + return incident + + def EventFromChain(self, event): + # event = self.Event2Update() + if isinstance(event, type(None)): + return None + self._event = event + incident = dict() + + # incident["arguments"] = { + # "whistle_start_time": "2020-08-25T22:22:45.00Z"} + startTime = event["start_time"] + "Z" + self._starttime = startTime + incident["id"] = dict() + eventGroup = rpc.get_object(event["event_group_id"]) + + sport = rpc.get_object(eventGroup["sport_id"]) + + # eventGroup = dict(eventGroup["name"])["identifier"] + eventGroup = dict(eventGroup["name"])["identifier"] + # sport = dict(sport["name"])["identifier"] + sport = dict(sport["name"])["identifier"] + sport = normalizer._get_sport_identifier(sport, True) + self._sport = sport + sportAlias = self.bookiesports[sport]["aliases"][0] + + eventGroup = normalizer._get_eventgroup_identifier( + sport, + eventGroup, + startTime, + True) + + self._eventGroup = eventGroup + # eventGroupAlias = self.EventGroupAlias(sport, eventGroup) + # eventGroupAlias = self.bookiesports[sport]["eventgroups"][ + # eventGroup]["aliases"][0] + + homeAway = event["name"][0][1] + self._homeAway = homeAway + home, away = self.HomeAway(homeAway) + eventScheme = self.EventScheme(sport, eventGroup) + homeAway = substitution([home, away], eventScheme) + home, away = self.HomeAway(homeAway) + + homeAlias = normalizer._get_participant_identifier( + sport, + eventGroup, + home, + True) + + awayAlias = normalizer._get_participant_identifier( + sport, + eventGroup, + away, + True) + + # incident["id"]["event_group_name"] = eventGroupAlias + incident["id"]["event_group_name"] = eventGroup + + incident["id"]["sport"] = sportAlias + + incident["id"]["start_time"] = startTime + incident["arguments"] = {"whistle_start_time": startTime} + # incident["id"]["start_time"] = "2020-08-25T22:00:00Z" + + incident["id"]["home"] = homeAlias + incident["id"]["away"] = awayAlias + incident["timestamp"] = date_to_string(datetime.now(tz=timezone.utc)) + incident["arguments"]["season"] = event["season"][0][1] + + self._incident = incident + # string = incident_to_string(incident) + + return incident + + def Update(self): + incident = self.CliUpdate() + if isinstance(incident, type(None)): + print("No incident to update") + return None, None + rs = [] + for potatoName in potatoNames: + r = self.Push2bos(incident, potatoName) + rs.append(r) + return rs + # r = self.Push2dp(incident) + + def Push2dp(self, incident): + self._incident = incident + string = incident_to_string(incident) + self._string = string + # normalize(string_to_incident(string), True) + params = dict() + params["manufacture"] = string + params["restrict_witness_group"] = "elizabeth" + params["token"] = "pbsabookie" + self._params = params + # r = requests.get(url=dps["local"], params=params) + # return r + + def Push2bos(self, incident, providerName): + _thread.start_new_thread(self.Push2bosMethod, (incident, providerName)) + print("thread started") + + def Push2bosMethod(self, incident, providerName): + string = incident_to_string(incident) + self._string = string + incident["unique_string"] = string + incident["provider_info"] = dict() + incident["provider_info"]["name"] = providerName + incident["provider_info"]["pushed"] = date_to_string( + datetime.now(tz=timezone.utc)) + self._incident = incident + incident = normalize(incident, True) + self._incident = incident + logger.info(str(incident)) + + while True: + proposalsOpen = rpc.get_proposed_transactions("1.2.1") + print("Len proposalsOpen: ", + len(proposalsOpen), " / ", self.maxOpenProposals) + if len(proposalsOpen) <= self.maxOpenProposals: + break + else: + time.sleep(60) + + # r = requests.post(url=bos["local"], json=incident) + rng = np.random.default_rng() + lBosApis = len(bosApis) + ks = rng.choice(lBosApis, size=lBosApis, replace=False) + # print(incident) + for k in ks: + # for api in bosApis: + print("inthread:", k) + api = list(bosApis[k].keys())[0] + acceptedProviderNames = list(bosApis[k].values())[0] + # print(api) + try: + if providerName in acceptedProviderNames: + print("providername in acepted list:", providerName) + requests.post(url=api, json=incident) + else: + print("providername NOT in acepted list:", providerName) + + except Exception as e: + print(e) + logger.warning(api + ": failed") + time.sleep(self.delayBetweenBosPushes) + try: + # FIXME, remove copy() + storage.insert_incident(incident.copy()) + except exceptions.DuplicateIncidentException as e: + print(e) + # We merely pass here since we have the incident already + # alerting anyone won't do anything + # traceback.print_exc() + pass + + print("thread finished") + return + + def OpenProposalsCount(self): + openProposalsCount = len(rpc.get_proposed_transactions("1.2.1")) + return openProposalsCount, self.maxOpenProposals + + def History(self, providerName): + collection = storage._get_collection(collection_name="incident") + historyGen = collection.find({"provider_info.name": { + "$eq": providerName}}) + + history = [] + for doc in historyGen: + history.append(doc) + history = history[::-1] + return history + + def Push2bosBetter(self, incident, providerNames): + string = incident_to_string(incident) + self._string = string + incident["unique_string"] = string + incident["provider_info"] = dict() + incident["provider_info"]["pushed"] = date_to_string( + datetime.now(tz=timezone.utc)) + self._incident = incident + incident = normalize(incident, True) + self._incident = incident + logger.info(str(incident)) + + # r = requests.post(url=bos["local"], json=incident) + rng = np.random.default_rng() + lBosApis = len(bosApis) + ks = rng.choice(lBosApis, size=lBosApis, replace=False) + # print(incident) + for k in ks: + # for api in bosApis: + print("inthread:", k) + api = bosApis[k] + for providerName in providerNames: + incident["provider_info"]["name"] = providerName + # print(api) + try: + requests.post(url=api, json=incident) + except Exception as e: + print(e) + logger.warning(api + ": failed") + time.sleep(self.delayBetweenBosPushes) + print("thread finished") + return + + def Push2bosAll(self, incident): + self.Push2bosBetter(incident, config["potatoNames"]) + # for potato in config["potatoNames"]: + # self.Push2bosMethod(incident, potato) + + def Create(self): + incident = self.CliManufactureCreateIncident() + rs = [] + for potatoName in potatoNames: + r = self.Push2bos(incident, potatoName) + rs.append(r) + # r = self.Push2bos(incident, "jemshid1") + # r2 = self.Push2bos(incident, "jemshid2") + # r = self.Push2dp(self._incident) + # return r, r2 + return rs + + def Choose(self): + # print("Choose u or c:") + print("u: Update event") + print("c: Create event") + choice = input("Enter your choice u/c: ") + if choice == "u": + self.Update() + elif choice == "c": + self.Create() + else: + print("You didn't make a relevant choice, try again") + + +if __name__ == "__main__": + cp = Cp() + # self.Choose() + # self.Create() + # incident = self.CliManufactureIncident() + string_to_incident + string_to_date diff --git a/couchpotato/example-config-bos-mint.yaml b/couchpotato/example-config-bos-mint.yaml new file mode 100644 index 0000000..f3cec4f --- /dev/null +++ b/couchpotato/example-config-bos-mint.yaml @@ -0,0 +1,39 @@ +debug: FALSE +project_name: PYTHON COUCH POTATO +project_sub_name: The Python Couch Potato project +secret_key: THINK CLOCK SMOG FLAG SMACK TINKER FLUNK # enter any random string +advanced_features: True + +sql_database: "sqlite:///{cwd}/bookied-local.db" + +connection: + use: hercules # enter your desired chain + + hercules: + node: + - wss://hercules.peerplays.download/api + nobroadcast: False + num_retries: 1 + +allowed_assets: + - BTFUN + - PPY + - TEST + - BTF +potatoNames: + - cpx + - cpy + +bosApis: + - http://hercules.peerplays.download:8010/trigger: + - cpi + - cp2 + +token: + - + +token_telegram: '' + +telegram_chat_ids: + - "" + diff --git a/couchpotato/feed.py b/couchpotato/feed.py new file mode 100644 index 0000000..aad807c --- /dev/null +++ b/couchpotato/feed.py @@ -0,0 +1,423 @@ +import telegram +import yaml +from dateutil.parser import parse +import requests +from bos_incidents.datestring import date_to_string, string_to_date +from datetime import datetime, timezone +import json +# import pandas as pd +from cp_local import Cp, rpc, config, normalize, substitution +import _thread +import time + +# leagueIds = [4328, 4391, 4387, 4380, 4424, 4335, 4332, 4331] +leagueIds = [4328, 4391, 4387, 4380, 4335, 4332, 4331] +# 4380 : NHL # Ice Hockey +# 4424 : MLB # Baseball +# 4328 : EPL +# 4391 : NFL +# 4387 : NBA +# 4335 : LaLiga +# 4332 : Serie A +# 4562 : Friendly International : International Friendlies +# 4482 : FA Cup +# 4481 : UEFA Europa Lague +# 4480 : UEFA Champions League +# 4331 : Bundesliga + + +INCIDENT_CALLS = [ + "create", # 0 + "in_progress", # 1 + "finish", # 2 + "result", # 3 + "canceled", # 4 + "dynamic_bmgs", # 5 +] + +# https://www.thesportsdb.com/api/v1/json/1/eventspastleague.php?id=4391 +# apiBase = "https://www.thesportsdb.com/api/v1/json/1/" +apiBase = "https://www.thesportsdb.com/api/v1/json/" +apiBase = apiBase + str(config["token"][0]) + "/" +apiEventsNextLeague = "eventsnextleague.php?id=" +apiEventsPastLeague = "eventspastleague.php?id=" +apiTeamsFromLeagueId = "lookup_all_teams.php?id=" + +apiAllLeagues = "all_leagues.php" + +tokenTelegram = config["token_telegram"] +telegramChatIds = config["telegram_chat_ids"] + + +class Feed: + + def __init__(self): + self.cp = Cp() + self.failedEvents = [] + self.constCheckPeriod = 60 * 60 * 24 # in seconds + self.maxOpenProposals = 1 + pass + + def Past15(self, leagueid): + url = apiBase + apiEventsPastLeague + str(leagueid) + schedule15 = requests.get(url) + schedule15 = schedule15.text + schedule15 = json.loads(schedule15) + events = schedule15["events"] + # return(schedule15) + # def CreateForApi(self, sport, eventGroup, home, away, startTime): + return events + + def Schedule15(self, leagueid): + url = apiBase + apiEventsNextLeague + str(leagueid) + schedule15 = requests.get(url) + self._schedule15 = schedule15 + schedule15 = schedule15.text + schedule15 = json.loads(schedule15) + events = schedule15["events"] + # return(schedule15) + # def CreateForApi(self, sport, eventGroup, home, away, startTime): + return events + + def Call(self, event, incident): + + startTime = string_to_date(incident["id"]["start_time"]) + now = datetime.now(timezone.utc) + self.now = now + self.startTime = startTime + + if (event["strPostponed"] == "yes") or ( + event["strStatus"] == "POST"): + incident["call"] = INCIDENT_CALLS[4] + # print("Postponed Event") + + elif ( + event["strStatus"] == "FT") or ( + event["strStatus"] == "Match Finished") or ( + event["strStatus"] == "AP") or ( + event["strStatus"] == "AOT") or ( + (now - startTime).days > 1): + incident["call"] = INCIDENT_CALLS[3] + incident["arguments"] = dict() + incident["arguments"]["home_score"] = event["intHomeScore"] + incident["arguments"]["away_score"] = event["intAwayScore"] + # print("Match Finished") + + elif ( + event["strStatus"] == "Not Started") or ( + event["strStatus"] == "NS"): + incident["call"] = INCIDENT_CALLS[0] + # print("Not started or NS") + + elif ( + startTime - now).days >= 1 and isinstance( + event["strStatus"], type(None)): + incident["call"] = INCIDENT_CALLS[0] + # print("None elif case and event created") + + elif (event["strStatus"] == "Second Half"): + incident["call"] = INCIDENT_CALLS[1] + # print('Second Half', "to in_progress", event["strFilename"]) + + else: + self.failedEvents.append(event) + print("Call Not Managed:") + return incident + + def ToCp(self, event): + sport = None + eventGroup = None + home = None + away = None + startTime = None + # strEvent = event["strEvent"] + # home, away = strEvent.split(" vs ") + sport = event["strSport"] + eventGroup = event["strLeague"] + home = event["strHomeTeam"] + away = event["strAwayTeam"] + dateEvent = event["dateEvent"] + strTime = event["strTime"] + # if len(strTime.split(":")[0]) == 1: + # strTime = "0" + strTime + startTime = dateEvent + "T" + strTime + "Z" + # print(startTime, type(startTime)) + startTime = date_to_string(parse(startTime)) + incident = self.CreateIncident( + sport, eventGroup, home, away, startTime) + + incident = self.Call(event, incident) + return incident + + def CreateIncident(self, sport, eventGroup, home, away, startTime): + incident = dict() + # incident["call"] = INCIDENT_CALLS[0] + + incident["id"] = dict() + incident["id"]["sport"] = sport + # eventGroupIdentifier = self.bookiesports[sport][ + # "eventgroups"][eventGroup]["identifier"] + # incident["id"]["event_group_name"] = eventGroupIdentifier + incident["id"]["event_group_name"] = eventGroup + # incident["id"]["event_group_name"] = self._eventGroup + # startTime = date_to_string(startTime) + incident["id"]["start_time"] = startTime + incident["arguments"] = {"whistle_start_time": startTime} + incident["id"]["home"] = home + incident["id"]["away"] = away + incident["timestamp"] = date_to_string(datetime.now(tz=timezone.utc)) + incident["arguments"]["season"] = "" + return incident + + def ForLeague(self, leagueId): + events = self.Schedule15(leagueId) + self.Push2Bos(events) + events = self.Past15(leagueId) + self.Push2Bos(events) + + def Push2Bos(self, events): + if isinstance(events, type(None)): + return + for k in range(len(events)): + while True: + proposalsOpen = rpc.get_proposed_transactions("1.2.1") + print("Len proposalsOpen: ", len(proposalsOpen)) + if len(proposalsOpen) <= self.maxOpenProposals: + break + else: + time.sleep(60) + event = events[k] + toCp = self.ToCp(event) + try: + self.cp.Push2bosAll(toCp) + except Exception as e: + # self.failedEvents.append(toCp) + self.failedEvents.append(event) + print("Failed Event: ", k, toCp) + print(e) + return + + def PushLeague(self, leagueid, call="create"): + if call == "create": + events = self.Schedule15(leagueid) + elif call == "result": + events = self.Past15(leagueid) + else: + print("Wrong call") + return + for k in range(len(events)): + event = events[k] + toCp = self.ToCp(event) + # print(k, "/", len(events), "-------event------: ", toCp) + print(k, "/", len(events)) + try: + self.cp.Push2bosAll(toCp) + except Exception as e: + print(e) + print("FAILED: ", event) + + def PushAll(self): + for leagueId in leagueIds: + self.ForLeague(leagueId) + # self.PushLeague(leagueId) + + def WhileForThread(self): + while self.flagWhileForThread == "run": + print('WhileForThreadStarted') + self.PushAll() + print('WhileForThreadOver') + time.sleep(self.constCheckPeriod) + print("WhileForThred EXITED") + + def Timed(self): + self.flagWhileForThread = "run" + _thread.start_new_thread(self.WhileForThread, ()) + + def EventsToDf(self, events): + pass + + def MatchingEvent(self, eventsFromFeed, eventFromChain): + for eventFromFeed in eventsFromFeed: + self._eventFromFeed = eventFromFeed + toCp = self.ToCp(eventFromFeed) + toCp = normalize(toCp) + if toCp["id"]["start_time"][:-1] == eventFromChain["start_time"]: + eventScheme = self.cp.EventScheme(toCp["id"]["sport"], toCp[ + "id"]["event_group_name"]) + home = toCp["id"]["home"] + away = toCp["id"]["away"] + homeAway = substitution([home, away], eventScheme) + if homeAway == eventFromChain["name"][0][1]: + return toCp + return None + + def MatchingEvents(self, leagueIds): + eventsFromFeed = [] + for leagueId in leagueIds: + # print(leagueId) + eventsFromFeed = eventsFromFeed + self.Past15(leagueId) + eventsFromChain = self.cp.EventsAllSortedForApi() + matchingEvents = [] + if isinstance(eventsFromChain, type(None)): + return matchingEvents + for k in range(len(eventsFromChain)): + # eventFromChain = eventsFromChain.iloc[k] + eventFromChain = eventsFromChain[k] + # for eventFromChain in eventsFromChain: + toCp = self.MatchingEvent(eventsFromFeed, eventFromChain) + # if not isinstance(toCp, type(None)): + matchingEvent = dict() + matchingEvent["eventFromChain"] = eventFromChain + matchingEvent["eventFromFeed"] = toCp + matchingEvents.append(matchingEvent) + return matchingEvents + + def MatchingEventsAll(self): + matchingEventsAll = self.MatchingEvents(leagueIds) + return matchingEventsAll + + +class Updater: + + def __init__(self): + self.cp = Cp() + self.delayMax = 3600 + self.delay = 60 + self.flagWhileForThread = "stop" + self.telegramBot = telegram.Bot(token=tokenTelegram) + pass + + def Update(self): + eventsAllSorted = self.cp.EventsAllSorted() + self.eventsAllSorted = eventsAllSorted + for k in range(len(eventsAllSorted)): + event = eventsAllSorted.iloc[k] + self.event = event + print(k, "/", len(eventsAllSorted), event["start_time"]) + startTime = event["start_time"] + "Z" + startTime = string_to_date(startTime) + nowInUtc = datetime.now(startTime.tzinfo) + if startTime <= nowInUtc: + if event["status"] == "upcoming": + for chatId in telegramChatIds: + text = "Update " + str(event) + " to in_progress!" + self.bot.sendMessage(chat_id=chatId, text=text) + + self.cp.UpdateForApi( + event, "in_progress") + + else: + time2nextEvent = startTime - nowInUtc + time2nextEvent = time2nextEvent.total_seconds() + print("Wait Started at:", nowInUtc) + if time2nextEvent > self.delayMax: + time.sleep(self.delayMax) + else: + time.sleep(time2nextEvent) + break + + def WhileForUpdate(self): + while self.flagWhileForThread == "run": + self.Update() + print("WhileForUpdateThred EXITED") + + def UpdateInThread(self): + self.flagWhileForThread = "run" + _thread.start_new_thread(self.WhileForUpdate, ()) + + +class Compare: + + def __init__(self): + pass + + +class FeedDetails: + + def __init__(self): + pass + + def Leagues(self): + leagues = requests.get(apiBase + apiAllLeagues) + leagues = leagues.text + leagues = json.loads(leagues) + leagues = leagues["leagues"] + return leagues + + def FindLeague(self): + leagues = self.Leagues() + while True: + query = input("Enter Search String For Leagues: ") + for k in range(len(leagues)): + # print(k, "/", len(leagues)) + if query in str(leagues[k]): + print(leagues[k]) + + def TeamsFromLeagueId(self, leagueid): + url = apiBase + apiTeamsFromLeagueId + str(leagueid) + teams = requests.get(url) + teams = teams.text + teams = json.loads(teams) + teams = teams["teams"] + # teamsShort = [] + for k in range(len(teams)): + team = teams[k] + print( + team[ + "strTeam"], "|", team[ + "strTeamShort"], "|", team["strAlternate"]) + # teamShort = dict() + # teamShort["str"] + # team["strTeam"] = + return teams + + def TeamsToDict(self, teams): + participants = [] + for i in teams: + participant = dict() + strTeam = i["strTeam"] + strAlternate = i["strAlternate"] + strTeamShort = i["strTeamShort"] + if isinstance(strAlternate, type(None)): + strAlternate = strTeam + elif len(strAlternate) == 0: + strAlternate = strTeam + if isinstance(strTeamShort, type(None)): + strTeamShort = strTeam + elif len(strTeamShort) == 0: + strTeamShort = strTeam + participant["identifier"] = strTeam + participant["aliases"] = [] + participant["aliases"].append(strTeam) + strAlternates = strAlternate.split(", ") + for item in strAlternates: + participant["aliases"].append(item) + # participant["aliases"].append(strAlternate) + participant["aliases"].append(strTeamShort) + participant["name"] = dict() + participant["name"]["en"] = strTeam + participant["name"]["sen"] = strTeamShort + participants.append(participant) + return participants + + def TeamsToYaml(self, leagueId, filename): + teams = self.TeamsFromLeagueId(leagueId) + participants = self.TeamsToDict(teams) + toFile = dict() + toFile["participants"] = participants + with open(filename, "w") as f: + f.write(yaml.dump(toFile)) + return toFile + + +if __name__ == "__main__": + feed = Feed() + self = feed + feedDetails = FeedDetails() + updater = Updater() + # leagues = feedDetails.Leagues() + # leagues = leagues["leagues"] + # print(leagues) + + # self = feed + string_to_date() diff --git a/couchpotato/game/autofetch.py b/couchpotato/game/autofetch.py deleted file mode 100644 index 3c76d17..0000000 --- a/couchpotato/game/autofetch.py +++ /dev/null @@ -1,58 +0,0 @@ -# # Create your views here. -# from django.http import Http404 , JsonResponse -# from django.shortcuts import render -# import json -# import requests -# import pytz, datetime - -# def AutoCreateCouchPotato(request): - -# create_value=dict() - -# games = requests.get('https://www.thesportsdb.com/api/v1/json/1/all_leagues.php') -# json_data = games.json() -# league = json_data['leagues'] -# res = next((l for l in league if l['strLeague'] == 'NFL'), None) - -# print(res['idLeague']) -# create_value['league'] = res['strLeague'] -# create_value['idleague'] = res['idLeague'] - -# season = requests.get('https://www.thesportsdb.com/api/v1/json/1/search_all_seasons.php?id='+create_value['idleague']) -# json_season = season.json()['seasons'][-1] -# print(json_season) -# create_value['season'] = json_season['strSeason'] - -# comming_events = requests.get('https://www.thesportsdb.com/api/v1/json/1/eventsnextleague.php?id='+create_value['idleague']) -# json_events = comming_events.json()['events'] -# print(json_events) - -# create_value['comming_events'] = json_events - - -# return JsonResponse( create_value) - - - -# def post_create(request): -# question_id = request.POST.get("id") -# option_text = request.POST.get("optiontext") -# question_id = int(question_id) -# if question_id == 1: -# request.session['sport'] = option_text -# elif question_id == 2: -# request.session['eventGroup'] = option_text -# elif question_id == 3: -# request.session['home'] = option_text -# elif question_id == 4: -# request.session['away'] = option_text -# elif question_id == 5: -# request.session['startTime'] = option_text -# data = {"sport":request.session['sport'].strip() ,"eventGroup":request.session['eventGroup'].strip(),"home":request.session['home'].strip(),"away":request.session['away'].strip(),"startTime":request.session['startTime'].strip()} -# print("Data " , data) -# result = requests.post('http://s3.jemshid.com:8000/sports/api/game/', data = data) -# if(len(eval(result.text)) > 0): -# return JsonResponse({'success':'Posted','message':result.text}) -# else: -# JsonResponse({'success':'Error','message':result.text}) -# return JsonResponse({'success':True,'message':'success'}) diff --git a/couchpotato/game/urls.py b/couchpotato/game/urls.py index 97f39f0..5e58234 100644 --- a/couchpotato/game/urls.py +++ b/couchpotato/game/urls.py @@ -4,10 +4,8 @@ from django.conf import settings from django.conf.urls.static import static from django.contrib.staticfiles.urls import staticfiles_urlpatterns -from home.tests import Test from django.views.static import serve from game.restapi import CreatePotatos , UpdatePotatos -# from game.autofetch import AutoCreateCouchPotato from django.urls import path, include from rest_framework import routers, serializers, viewsets @@ -15,7 +13,6 @@ path('create_potato/',CreatePotatos.as_view(),name= 'create_potato'), path('update_potato/',UpdatePotatos.as_view(),name= 'update_potato'), - # path('auto_create_potato/',AutoCreateCouchPotato,name= 'auto_create_potato'), path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), ] diff --git a/couchpotato/game/views.py b/couchpotato/game/views.py index 71b6771..dbdb1b2 100644 --- a/couchpotato/game/views.py +++ b/couchpotato/game/views.py @@ -6,6 +6,20 @@ import cp_local cp = cp_local.Cp() +from feed import Feed +fd = Feed() + +def GetMatchingEvents(): + listDist = fd.MatchingEventsAll() + return listDist + +def GetOpenProposalsCount(): + openproposals , maxproposals = cp.OpenProposalsCount() + return [openproposals ,maxproposals ] + +def GetHistory(providername): + return cp.History(providername) + def GetEvents(params={}): rDict = dict() sport = None @@ -132,3 +146,5 @@ def UpdatePotato(record): # print(rDict) # print(e) return rDict + + diff --git a/couchpotato/home/events.json b/couchpotato/home/events.json deleted file mode 100644 index 173cb7d..0000000 --- a/couchpotato/home/events.json +++ /dev/null @@ -1,3 +0,0 @@ - - {"1": - {"id": "1.22.43", "name": [["en", "Miami Heat @ Los Angeles Lakers"]], "season": [["en", ""]], "start_time": "2020-10-10T06:30:00", "event_group_id": "1.21.15", "scores": [], "status": "finished"}, "2": {"id": "1.22.44", "name": [["en", "Los Angeles Lakers @ Miami Heat"]], "season": [["en", ""]], "start_time": "2020-10-12T05:00:00", "event_group_id": "1.21.15", "scores": [], "status": "in_progress"}, "3": {"id": "1.22.48", "name": [["en", "Utah Jazz @ Toronto Raptors"]], "season": [["en", ""]], "start_time": "2020-10-29T22:00:00", "event_group_id": "1.21.15", "scores": [], "status": "upcoming"}, "4": {"id": "1.22.49", "name": [["en", "Orlando Magic @ Oklahoma City Thunder"]], "season": [["en", ""]], "start_time": "2020-10-29T22:00:00", "event_group_id": "1.21.15", "scores": [], "status": "upcoming"}} diff --git a/couchpotato/home/forms.py b/couchpotato/home/forms.py index 183c7fc..a1d4add 100644 --- a/couchpotato/home/forms.py +++ b/couchpotato/home/forms.py @@ -1,7 +1,52 @@ from django import forms from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User +from django.contrib.auth import login, authenticate +from django.contrib.auth.forms import AuthenticationForm + + +class LoginForm(AuthenticationForm): + def confirm_login_allowed(self, user): + if not user.is_active: + raise forms.ValidationError( + 'The user is awating admin approval', + code='inactive', + ) + elif self.user_cache is None: + raise forms.ValidationError( + self.error_messages['invalid_login'], + code='invalid_login', + params={'username': self.username_field.verbose_name}, + ) + def clean(self): + username = self.cleaned_data.get('username') + password = self.cleaned_data.get('password') + if username is None or username is '': + raise forms.ValidationError( + 'Username cannot be left blank', + code='invalid_login', + params={'username': self.username_field.verbose_name}, + ) + elif username is not None and password: + self.user_cache = authenticate(self.request, username=username, password=password) + print(self.user_cache) + if self.user_cache is None: + try: + user_temp = User.objects.get(username=username) + except: + user_temp = None + + if user_temp is not None: + self.confirm_login_allowed(user_temp) + else: + raise forms.ValidationError( + self.error_messages['invalid_login'], + code='invalid_login', + params={'username': self.username_field.verbose_name}, + ) + + return self.cleaned_data class SignUpForm(UserCreationForm): # first_name = forms.CharField(label='First Name') diff --git a/couchpotato/home/questions.json b/couchpotato/home/questions.json deleted file mode 100644 index 7282912..0000000 --- a/couchpotato/home/questions.json +++ /dev/null @@ -1,24 +0,0 @@ - -[ - { - "list" : { "1":"Male","2":"Female" , "3":"Other"} , - "question":"Question No 1", - "islast": false, - "question_id":1 - }, - { - "list" : { "1":"2 Male ","2":"2 Female" , "3":"2 Other"} , - "question":"Question No 2", - "islast": false, - "question_id":2 - }, - - { - "list" : { "1":"3 Male ","2":"3 Female" , "3":"3 Other"} , - "question":"Question No 3", - "islast": true, - "question_id":3 - } - - -] \ No newline at end of file diff --git a/couchpotato/home/templates/admin.html b/couchpotato/home/templates/admin.html index 6963ccf..8cae738 100644 --- a/couchpotato/home/templates/admin.html +++ b/couchpotato/home/templates/admin.html @@ -19,7 +19,7 @@
-

Application Settings

+

Application Settings


+
+

Home Team

+ +
+
+
+

Away Team

+ +
+
+ + + +
+

Start Time

+ + +
@@ -56,32 +98,27 @@

{{heading}}

+
+ +
+
+ +

- {% endif %} - -
+ +
- {% if question_id > 1 %} - - {% endif %} - {% if not islast %} - - - - {% endif %} - - {% if islast %} - {% endif %} + Return to Home @@ -134,21 +171,91 @@

{{heading}}

}) - $('input[type=radio]').change(function() - { - if (this.checked) + $('select').on('change', function() { + + + // console.log("selected value" , this.value ); + // console.log("selected text" , $(this).find("option:selected").text()); + // console.log((this).id) + id = parseInt((this).id) + + new_next_select_id = id + 1 + + if (id == 1 || id == 2){ + $('#3').html('') + $('#4').html('') + } + sport = $('.games').find("option:selected").text() + groups = $('.groups').find("option:selected").text() + home = $('.home').find("option:selected").text() + away = $('.away').find("option:selected").text() + + + + + $.post("/select/", { - var element = this - $('input[type=radio]').each(function(){ - // console.log($(this)) - if(element != this){ - $(this).prop('checked',false) - } - }); + num: new_next_select_id, + sport:sport, + eventGroup:groups, + home:home, + away:away, + csrfmiddlewaretoken: '{{ csrf_token }}' , + }, + function(data, status){ + + var obj = data.list + $('#'+new_next_select_id).html('') + if (data.list[1] != 'status'){ + Object.keys(obj).forEach(function(key) { + + $('#'+new_next_select_id).append("") + }); + } + + }); + + + }); + + function validate(){ + + var sport = $('.games').find("option:selected").val() + var groups = $('.groups').find("option:selected").val() + var home = $('.home').find("option:selected").val() + var away = $('.away').find("option:selected").val() + var date_val = $('#datetimepicker1 input').val() + + if(parseInt(sport) === 999){ + $('#error_msg').html('Please select a sport') + return false + } + else if(parseInt(groups) === 999){ + $('#error_msg').html('Please select a league') + return false + } + else if(parseInt(home) === 999){ + $('#error_msg').html('Please select a home team') + return false } + else if(parseInt(away) === 999){ + $('#error_msg').html('Please select a away team') + return false + } + else if(typeof date_val === 'undefined' || date_val === ""){ + $('#error_msg').html('Please select a date time') + return false + } + else{ + $('#error_msg').html('') + return true + } + + + - }); + } $("#create_submit").click(function(){ @@ -156,65 +263,34 @@

{{heading}}

var selectedtext = $("form input[type='radio']:checked").next('label:first').html() var next_num = parseInt($("form").attr("id")) + 1 + var date_val = $('#datetimepicker1 input').val() - var d = new Date(date_val) - // console.log(d.getTimezoneOffset()) + var d = new Date(date_val) + question_id = 5 - // var utc = new Date(d.getTime() + d.getTimezoneOffset() * 60000); - // console.log("Current date ", d.toString()) - // console.log("To utc inbuild met" , d.toUTCString()) - // console.log("UTC conversion " , utc.toString()) - // console.log("ISO conversion " , d.toISOString()) - - - if (typeof date_val !== 'undefined' & date_val !== ""){ + if (validate()){ + $.post("/post_create", { - id: $("form").attr("id"), + id: question_id, optionvalue: 'date', optiontext : d.toISOString(), csrfmiddlewaretoken: '{{ csrf_token }}' , }, function(data, status){ - alert(data.success) - window.location.href = '/' + if (data.success == 'Posted'){ + alert(data.message) + window.location.href = '/' + } + + + }); } }) - $("#next").click(function(){ - - - var selected = $("form input[type='radio']:checked"); - var selectedtext = $("form input[type='radio']:checked").next('label:first').html() - - var next_num = parseInt($("form").attr("id")) + 1 - // console.log(selectedtext) - - if (typeof selectedtext !== 'undefined'){ - $.post("/post_create", - { - id: $("form").attr("id"), - optionvalue: selected.val(), - optiontext : selectedtext, - csrfmiddlewaretoken: '{{ csrf_token }}' , - }, - function(data, status){ - window.location.href = '/create/'+next_num - }); - } - - - }); - - $("#back").click(function(){ - - - var next_num = parseInt($("form").attr("id")) - 1 - window.location.href = '/create/'+next_num - - }); + diff --git a/couchpotato/home/templates/history.html b/couchpotato/home/templates/history.html new file mode 100644 index 0000000..e53202f --- /dev/null +++ b/couchpotato/home/templates/history.html @@ -0,0 +1,231 @@ + + + + + Couch Potato + + + + + + + + + + + + + + {% include "navbar.html" %} + +
+
+ +

+

Number of Open Proposals: {{ proposals.0 }} / {{ proposals.1 }}

+ + + + +
+ + + + + + + + + + + + + + + + + + + + {% for a in data.items %} + + + + + + + + + + + + + + + + + + + + + + + + {% endfor %} + + + +
Start TimeSportEvent Group NameHomeAwayHome ScoreAway ScoreTimestampUnique StringId stringName
+ {{ a.1.id.start_time }} + + {{ a.1.id.sport }} + + {{ a.1.id.event_group_name }} + + {{ a.1.id.home }} + + {{ a.1.id.away }} + + {{ a.1.arguments.home_score }} + + {{ a.1.arguments.away_score }} + + {{ a.1.timestamp }} + + {{ a.1.unique_string }} + + {{ a.1.id_string }} + + {{ a.1.provider_info.name }} +
+ + + + + Return to Home + +
+ + +
+
+ + + + + + + + + + + + + + + + + + diff --git a/couchpotato/home/templates/index.html b/couchpotato/home/templates/index.html index 4363ec4..d8c2051 100644 --- a/couchpotato/home/templates/index.html +++ b/couchpotato/home/templates/index.html @@ -12,6 +12,17 @@ + @@ -29,10 +40,30 @@

- + +
+
+
+ CREATE +
+
+ UPDATE +
+
+ +
+
+ HISTORY +
+
+ CALENDAR +
+
+
+ + + + diff --git a/couchpotato/home/templates/login.html b/couchpotato/home/templates/login.html index e9e595f..572f187 100644 --- a/couchpotato/home/templates/login.html +++ b/couchpotato/home/templates/login.html @@ -18,12 +18,7 @@ - - - + @@ -52,8 +47,7 @@
- -
+
@@ -70,14 +64,15 @@
- {% if messages %} -
    - {% for message in messages %} + {% if messages %} + + {% for message in messages %} + {{message}} + + {% endfor %} + -
  • {{ message }}
  • - {% endfor %} -
- {% endif %} + {% endif %} @@ -93,20 +88,7 @@
- +
@@ -118,29 +100,14 @@

...or login with:

- - + - + diff --git a/couchpotato/home/templates/navbar.html b/couchpotato/home/templates/navbar.html index d42b253..7d35aa5 100644 --- a/couchpotato/home/templates/navbar.html +++ b/couchpotato/home/templates/navbar.html @@ -4,9 +4,13 @@ .rounded-circle{ width: 40px; } + body{background-color: beige;} + nav{ + background-color: beige !important; + } -