EasyAppointments
This commit is contained in:
parent
a89dcede99
commit
337cd46f24
7 changed files with 345 additions and 26 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
data.json
|
||||
session.txt
|
||||
__pycache__
|
||||
easyappointments-flow.md
|
208
commands.py
208
commands.py
|
@ -1,5 +1,6 @@
|
|||
import random
|
||||
import features
|
||||
import json
|
||||
|
||||
api = features.API()
|
||||
debug = False
|
||||
|
@ -17,8 +18,11 @@ def handle_command(sender, message):
|
|||
result = commands[state[0]](state, message, sender)
|
||||
return result
|
||||
except Exception as e:
|
||||
if __name__ != '__main__':
|
||||
state = []
|
||||
api.update_user_state(sender, state)
|
||||
return {
|
||||
"response": f"⚠️Error⚠️"
|
||||
"response": f"⚠️Error⚠️\n{e}"
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -202,13 +206,202 @@ def meetings(state,message,sender):
|
|||
'response':api.appointments.list_upcoming_appointments(sender)
|
||||
}
|
||||
|
||||
def appointments():
|
||||
def register_customer(state,message,sender):
|
||||
if api.appointments.is_customer(sender):
|
||||
return {'response':"Already registered."}
|
||||
if state == ['!register2']:
|
||||
return {
|
||||
'response':'What is your first name?'
|
||||
}
|
||||
|
||||
if state == []:
|
||||
state = ['!register']
|
||||
api.update_user_state(sender, state)
|
||||
return {
|
||||
'response':'What is your first name?'
|
||||
}
|
||||
if len(state) == 1:
|
||||
state.append(message)
|
||||
api.update_user_state(sender, state)
|
||||
return {
|
||||
'response':'What is your last name?'
|
||||
}
|
||||
if len(state) == 2:
|
||||
state.append(message)
|
||||
api.update_user_state(sender, state)
|
||||
return {
|
||||
'response':'What is your e-mail?'
|
||||
}
|
||||
if len(state) == 3:
|
||||
state.append(message)
|
||||
api.update_user_state(sender, state)
|
||||
return {
|
||||
'response':"What is your phone number?"
|
||||
}
|
||||
if len(state) == 4:
|
||||
state.append(message)
|
||||
api.update_user_state(sender, state)
|
||||
resp = f"You've entered: `{state[1]} {state[2]} ({state[3]} / {state[4]})`\n**Is this correct?**\nIf so, respond with:Yes\nIf not, to restart respond with :No\nYou can always cancel with:nevermind"
|
||||
return {
|
||||
'response':resp
|
||||
}
|
||||
if len(state) == 5:
|
||||
if "yes" in message.lower():
|
||||
data = {
|
||||
"firstName":state[1],
|
||||
"lastName":state[2],
|
||||
"email":state[3],
|
||||
"phone":state[4],
|
||||
"notes":f"matrix:{sender}"
|
||||
}
|
||||
if sender == "admin":
|
||||
dat = json.dumps(data)
|
||||
print(f"Data:\n{dat}")
|
||||
if api.appointments.register_customer(data):
|
||||
if(state[0]=='!register2'):
|
||||
state = ['!book']
|
||||
api.update_user_state(sender, state)
|
||||
return {'response':"Successfully registered.\n\n"+booking(['!book'],'',sender)['response']}
|
||||
state = []
|
||||
api.update_user_state(sender, state)
|
||||
return{'response':"Successfully registered."}
|
||||
else:
|
||||
return{'response':"Error, please try again."}
|
||||
api.update_user_state(sender, [])
|
||||
return {
|
||||
"response": None,
|
||||
state: []
|
||||
'response':''
|
||||
}
|
||||
|
||||
def select_service(state,message,sender):
|
||||
if len(state) >= 2:
|
||||
return select_provider(state, message, sender)
|
||||
# ['!book','select-service']
|
||||
if message == "!book":
|
||||
return {'response':api.select_service()}
|
||||
else:
|
||||
try:
|
||||
state.append(api.appointments.get_services()[int(message)]['id'])
|
||||
api.update_user_state(sender, state)
|
||||
return booking(state, "", sender)
|
||||
except:
|
||||
return {'response':'Error selecting service\nTo cancel type:nevermind'}
|
||||
|
||||
def select_provider(state,message,sender):
|
||||
if len(state) >= 3:
|
||||
return select_time(state, message, sender)
|
||||
if message == "":
|
||||
return {'response':api.select_provider()}
|
||||
try:
|
||||
state.append(api.appointments.get_providers()[int(message)]['id'])
|
||||
api.update_user_state(sender, state)
|
||||
return booking(state,"",sender)
|
||||
except:
|
||||
return {'response':'Error selecting provider\nTo cancel type:nevermind'}
|
||||
|
||||
|
||||
def select_time(state,message,sender):
|
||||
if len(state) >= 5:
|
||||
return booking(state, message, sender)
|
||||
api.update_data()
|
||||
# ['!book','select-time']
|
||||
if len(state) == 3:
|
||||
msg = api.select_times(state[1],state[2],message)
|
||||
if msg == False:
|
||||
return {'response':"Please enter a date you'd like to book (\"YYYY-MM-DD\" format)"}
|
||||
state.append(message)
|
||||
api.update_user_state(sender, state)
|
||||
return {'response':msg}
|
||||
if len(state) == 4:
|
||||
times = api.appointments.get_availabilities(state[1], state[2], state[3])
|
||||
if message in times:
|
||||
state.append(message)
|
||||
time = None
|
||||
try:
|
||||
time = times[int(message)-1]
|
||||
state.append(time)
|
||||
api.update_user_state(sender, state)
|
||||
return booking(state, message, sender)
|
||||
except:
|
||||
return {'response':api.select_times(state[1],state[2],state[3])}
|
||||
return {'response':error}
|
||||
|
||||
def booking(state,message,sender):
|
||||
if len(state) > 5:
|
||||
state = []
|
||||
if state==[]:
|
||||
state.append("!book")
|
||||
api.update_user_state(sender, state)
|
||||
"""
|
||||
To book an appointment, you need (in order):
|
||||
* the customer ID (now mapped to mxid) (0?)
|
||||
* The service id (1)
|
||||
* the provider id (2)
|
||||
* the start date & time (3)
|
||||
"""
|
||||
#Quick checks
|
||||
customer = api.appointments.is_customer(sender)
|
||||
if customer == False:
|
||||
return register_customer([], "", sender)
|
||||
|
||||
#Service check
|
||||
service = None
|
||||
if len(api.appointments.services) == 0:
|
||||
return {'response':"Error: there are no services"}
|
||||
if len(api.appointments.services) == 1:
|
||||
service = api.appointments.get_services()[0]
|
||||
state.append(service)
|
||||
api.update_user_state(sender, state)
|
||||
return booking(state, message, sender)
|
||||
if len(state) >= 2:
|
||||
service = state[1]
|
||||
if service == None:
|
||||
return select_service(state, message, sender)
|
||||
|
||||
|
||||
#Provider check
|
||||
|
||||
provider = None
|
||||
if len(api.appointments.providers) == 0:
|
||||
return {'response':'error: there are no providers'}
|
||||
if len(state) >= 3:
|
||||
provider = state[2]
|
||||
elif len(api.appointments.providers) == 1:
|
||||
provider = api.appointments.get_providers()[0]['id']
|
||||
if service != None:
|
||||
state.append(provider)
|
||||
api.update_user_state(sender, state)
|
||||
if provider == None:
|
||||
return select_provider(state, message, sender)
|
||||
|
||||
time = None
|
||||
if len(state) == 5:
|
||||
time = state[4]
|
||||
if time == None:
|
||||
return select_time(state, message, sender)
|
||||
data = {
|
||||
"start": state[3] + " "+ state[4]+":00",
|
||||
"customerId":int(customer),
|
||||
"providerId":int(provider),
|
||||
"serviceId":int(service)
|
||||
}
|
||||
result = api.appointments.register_appointment(data)
|
||||
if result != False:
|
||||
state = []
|
||||
api.update_user_state(sender, state)
|
||||
return{'response':'Successfully registered appointment!'}
|
||||
else:
|
||||
state = []
|
||||
api.update_user_state(sender, state)
|
||||
print(result)
|
||||
return{'response':"Error: please try again"}
|
||||
|
||||
return{'response':"Error: please try again"}
|
||||
|
||||
|
||||
def services(state,message,sender):
|
||||
return {
|
||||
'response':api.list_services()
|
||||
}
|
||||
|
||||
commands = {
|
||||
"nevermind": nevermind,
|
||||
|
@ -222,7 +415,11 @@ commands = {
|
|||
"!remove footer": remove_footer,
|
||||
"!add admin": add_admin,
|
||||
"!remove admin": remove_admin,
|
||||
"meetings":meetings
|
||||
"!meetings":meetings,
|
||||
"!register":register_customer,
|
||||
"!register2":register_customer,
|
||||
"!book":booking,
|
||||
"!services":services
|
||||
|
||||
}
|
||||
|
||||
|
@ -235,3 +432,4 @@ if __name__ == '__main__':
|
|||
msg = input("user:")
|
||||
print("bot:"+handle_command(user, msg)['response'])
|
||||
# print("state:",user)
|
||||
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
"username": "bot",
|
||||
"password": "hunter2",
|
||||
"homeserver": "http://localhost:8008",
|
||||
"easyappointments": {
|
||||
"token": "secrettoken",
|
||||
"url": "http://localhost/easyappointments/index.php"
|
||||
},
|
||||
"faq": {
|
||||
"header": "# Simple example FAQ",
|
||||
"questions": [{
|
||||
|
|
|
@ -4,12 +4,15 @@ class easyappointments:
|
|||
def __init__(self,token,url):
|
||||
self.token = token
|
||||
self.url = url
|
||||
self.headers = {"Authorization":"Bearer secrettoken"}
|
||||
self.headers = {"Authorization":f"Bearer {token}"}
|
||||
self.appointments = {}
|
||||
self.services = {}
|
||||
self.providers = {}
|
||||
self.customers = {}
|
||||
self.update_data()
|
||||
try:
|
||||
self.update_data()
|
||||
except:
|
||||
print("Failed to connect to easyappointments!")
|
||||
|
||||
def get_appointments(self):
|
||||
data = requests.get(self.url+'/api/v1/appointments',headers=self.headers)
|
||||
|
@ -24,6 +27,13 @@ class easyappointments:
|
|||
data = requests.get(self.url+'/api/v1/customers',headers=self.headers)
|
||||
return data.json()
|
||||
|
||||
def get_availabilities(self,service,provider,date):
|
||||
try:
|
||||
data = requests.get(self.url+f"/api/v1/availabilities?serviceId={service}&providerId={provider}&date={date}",headers=self.headers)
|
||||
return data.json()
|
||||
except:
|
||||
return False
|
||||
|
||||
def update_data(self):
|
||||
appointments = self.get_appointments()
|
||||
for a in appointments:
|
||||
|
@ -43,6 +53,7 @@ class easyappointments:
|
|||
for c in customers:
|
||||
if mxid in c['notes']:
|
||||
return c['id']
|
||||
|
||||
return False
|
||||
|
||||
def is_provider(self,mxid):
|
||||
|
@ -50,7 +61,7 @@ class easyappointments:
|
|||
for p in providers:
|
||||
if mxid in p['notes']:
|
||||
return p['id']
|
||||
|
||||
return -1
|
||||
def get_upcoming_appointments(self,mxid):
|
||||
#get services & customers
|
||||
id = self.is_provider(mxid)
|
||||
|
@ -64,6 +75,9 @@ class easyappointments:
|
|||
else:
|
||||
return []
|
||||
|
||||
|
||||
|
||||
|
||||
def list_upcoming_appointments(self,mxid):
|
||||
apts = self.get_upcoming_appointments(mxid)
|
||||
if apts == []:
|
||||
|
@ -75,6 +89,8 @@ class easyappointments:
|
|||
output += f"## {service} with {customer}\nTime:{a['start']}\n"
|
||||
return output
|
||||
|
||||
|
||||
|
||||
def register_customer(self,customer_data):
|
||||
#customer data
|
||||
"""
|
||||
|
@ -86,8 +102,50 @@ class easyappointments:
|
|||
"notes":"matrix:mxid"
|
||||
}
|
||||
"""
|
||||
id = requests.post(self.url+'/api/v1/customers',headers=self.headers,data=json.dumps(customer_data)).json()['id']
|
||||
return id
|
||||
try:
|
||||
id = requests.post(self.url+'/api/v1/customers',headers=self.headers,data=json.dumps(customer_data)).json()['id']
|
||||
self.update_data()
|
||||
return id
|
||||
except:
|
||||
return False
|
||||
|
||||
def register_appointment(self,appointment_data):
|
||||
#appointment data
|
||||
"""{
|
||||
"start":"YY-MM-DD HH:MM:SS",
|
||||
"customerId":9,
|
||||
"providerId":4,
|
||||
"serviceId:4
|
||||
}
|
||||
"""
|
||||
print("Registering appointment:")
|
||||
print(json.dumps(appointment_data))
|
||||
result = requests.post(
|
||||
self.url+'/api/v1/appointments',
|
||||
headers = self.headers,
|
||||
data=json.dumps(appointment_data)
|
||||
)
|
||||
id = result.json()['id']
|
||||
if id:
|
||||
return id
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
cdat = {
|
||||
"firstName":"Test",
|
||||
"lastName":"",
|
||||
"email":"test@testing.xa",
|
||||
"phone":"888-888-8888",
|
||||
"notes":"matrix:@lol:testing"
|
||||
}
|
||||
adat = {
|
||||
"start":"2022-09-28 09:00:00",
|
||||
"customerId":8,
|
||||
"providerId":4,
|
||||
"serviceId":2
|
||||
}
|
||||
|
||||
easy = easyappointments('secrettoken', 'http://localhost:8787/easyappointments/index.php')
|
||||
|
|
1
error.log
Normal file
1
error.log
Normal file
|
@ -0,0 +1 @@
|
|||
Error:@gabriel:libresolutions.network: !bookError:@gabriel:libresolutions.network: !bookError:@gabriel:libresolutions.network: !register
|
68
features.py
68
features.py
|
@ -1,11 +1,18 @@
|
|||
import json
|
||||
import requests
|
||||
import easyappointments
|
||||
import datetime
|
||||
"""
|
||||
Features
|
||||
This is the main API for executing functions with data
|
||||
"""
|
||||
|
||||
def check_date(date):
|
||||
try:
|
||||
datetime.datetime.strptime(date,"%Y-%m-%d")
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
class API:
|
||||
def __init__(self):
|
||||
|
@ -16,6 +23,7 @@ class API:
|
|||
def update_data(self):
|
||||
with open('data.json','r') as f:
|
||||
self.data = json.loads(f.read())
|
||||
|
||||
def save(self):
|
||||
with open('data.json','w') as f:
|
||||
f.write(json.dumps(self.data,indent=2))
|
||||
|
@ -25,11 +33,9 @@ class API:
|
|||
|
||||
#Administration
|
||||
def is_admin(self,handle):
|
||||
self.update_data()
|
||||
#return bool
|
||||
pass
|
||||
def add_admin(self,handle):
|
||||
self.update_data()
|
||||
#return bool
|
||||
if self.is_admin(handle):
|
||||
return True
|
||||
|
@ -38,7 +44,6 @@ class API:
|
|||
self.save()
|
||||
return True
|
||||
def remove_admin(self,handle):
|
||||
self.update_data()
|
||||
#return bool
|
||||
if self.is_admin(handle):
|
||||
i = self.data["admins"].index(handle)
|
||||
|
@ -51,7 +56,6 @@ class API:
|
|||
|
||||
#state management
|
||||
def get_user_state(self,handle):
|
||||
self.update_data()
|
||||
if handle not in self.data["users"]:
|
||||
self.data["users"][handle]={"state":[]}
|
||||
self.save()
|
||||
|
@ -67,7 +71,6 @@ class API:
|
|||
|
||||
#FAQ
|
||||
def get_faq_string(self):
|
||||
self.update_data()
|
||||
faq = self.data["faq"]
|
||||
return faq["header"] + "".join(
|
||||
["\n# "+q["question"]+"\n"+q["answer"]+"\n" for q in faq["questions"]]
|
||||
|
@ -121,6 +124,57 @@ class API:
|
|||
self.update_data()
|
||||
self.appointments.list_upcoming_appointments(mxid)
|
||||
pass
|
||||
def list_services(self):
|
||||
msg = "## Services:"
|
||||
for i in self.appointments.services:
|
||||
service = self.appointments.services[i]
|
||||
name = service['name']
|
||||
price = str(service['price']) + service['currency']
|
||||
description = service['description']
|
||||
msg += f"\n### {name}\nPrice:{price}\n{description}"
|
||||
return msg
|
||||
|
||||
|
||||
def select_service(self):
|
||||
msg = "## Choose a service:"
|
||||
counter = 1
|
||||
for i in self.appointments.services:
|
||||
service = self.appointments.services[i]
|
||||
name = f"#{counter}: " + service['name']
|
||||
price = str(service['price']) + service['currency']
|
||||
description = service['description']
|
||||
msg += f"\n### {name}\nPrice:{price}\n{description}"
|
||||
counter += 1
|
||||
msg += "\nPlease enter the # of the service:"
|
||||
return msg
|
||||
|
||||
def select_provider(self):
|
||||
msg = "## Choose a provider:"
|
||||
counter = 1
|
||||
for p in self.appointments.get_providers():
|
||||
name = p['firstName']+" "+p['lastName']
|
||||
msg += f"\n* #{counter}: {name}"
|
||||
counter += 1
|
||||
msg += "\nPlease enter the # of the provider"
|
||||
return msg
|
||||
|
||||
|
||||
|
||||
def select_times(self,service,provider,date):
|
||||
data = self.appointments.get_availabilities(service, provider, date)
|
||||
if data == False or check_date(date) == False:
|
||||
return False
|
||||
msg = f"## Choose a time for {date}:\n"
|
||||
counter = 1
|
||||
for t in data:
|
||||
msg += f"{counter}){t} "
|
||||
counter +=1
|
||||
msg +="\nPlease enter the # of time"
|
||||
return msg
|
||||
|
||||
|
||||
|
||||
|
||||
def request_meeting(self):
|
||||
self.update_data()
|
||||
pass
|
||||
|
@ -130,5 +184,5 @@ class API:
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
storeAPI = API()
|
||||
print("Storage loaded.\n",storeAPI.data['username'])
|
||||
api = API()
|
||||
print("Storage loaded.\n",api.data['username'])
|
||||
|
|
17
main.py
17
main.py
|
@ -13,13 +13,16 @@ bot = botlib.Bot(creds)
|
|||
|
||||
@bot.listener.on_message_event
|
||||
async def message(room, message):
|
||||
result = commands.handle_command(message.sender, message.body)
|
||||
if result['response'] != None and result['response'] != "":
|
||||
await bot.api.send_markdown_message(
|
||||
room.room_id,
|
||||
result['response']
|
||||
)
|
||||
|
||||
try:
|
||||
result = commands.handle_command(message.sender, message.body)
|
||||
if result['response'] != None and result['response'] != "":
|
||||
await bot.api.send_markdown_message(
|
||||
room.room_id,
|
||||
result['response']
|
||||
)
|
||||
except:
|
||||
with open("error.log",'a') as f:
|
||||
f.write(f"Error:{message}")
|
||||
|
||||
@bot.listener.on_custom_event(nio.InviteMemberEvent)
|
||||
async def example(room, event):
|
||||
|
|
Loading…
Reference in a new issue