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" %}
+
+
+
+
+
+
+ Theme System:
+
+
+ Bootstrap 4
+ unthemed
+
+
+
+
+ Theme Name:
+
+
+ Default
+ Cerulean
+ Cosmo
+ Cyborg
+ Darkly
+ Flatly
+ Journal
+ Litera
+ Lumen
+ Lux
+ Materia
+ Minty
+ Pulse
+ Sandstone
+ Simplex
+ Sketchy
+ Slate
+ Solar
+ Spacelab
+ Superhero
+ United
+ Yeti
+
+
+
+
+
+
+
+
+
+
+
+
+
+
loading...
+
+
+
+
+
+
+
+
+
+
+
+
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
+
+
- {% if question_id > 1 %}
- Back
- {% endif %}
- {% if not islast %}
-
- Next
-
- {% endif %}
-
- {% if islast %}
Submit
- {% 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('Select One ')
+ $('#4').html('Select One ')
+ }
+ 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('Select One ')
+ if (data.list[1] != 'status'){
+ Object.keys(obj).forEach(function(key) {
+
+ $('#'+new_next_select_id).append(""+obj[key] + " ")
+ });
+ }
+
+ });
+
+
+ });
+
+ 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
-
- });
+
+ {% include "navbar.html" %}
+
+
+
+
+
+
Number of Open Proposals: {{ proposals.0 }} / {{ proposals.1 }}
+
+
+
+
+
+
+
+
+
+ Start Time
+ Sport
+ Event Group Name
+ Home
+ Away
+ Home Score
+ Away Score
+ Timestamp
+ Unique String
+ Id string
+ Name
+
+
+
+
+ {% for a in data.items %}
+
+
+
+
+ {{ 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 }}
+
+
+
+
+
+
+
+ {% endfor %}
+
+
+
+
+
+
+
+
+ Return to Home
+
+
+
+
+
+
+
+
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 @@
+
+
+
+