Repository navigation
Expand file tree
/
Copy pathpost_operations.py
More file actions
466 lines (420 loc) · 19.9 KB
/
Copy pathpost_operations.py
File metadata and controls
466 lines (420 loc) · 19.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
from Database import Database
from datetime import date
import sqlite3
# from pprint import pprint
class Post_user:
def __init__(self, user):
self.user = user
self.posts = 0
self.db = Database()
def makepost(self):
makingpost = True
while makingpost:
# Collect post information
title = input('Enter your title: ')
body = input('Enter the body of your post: ')
# Make sure user wants to post this
print(title)
print(body)
postcheck = input('Is this what you would like to post? (Y/N)').lower()
if postcheck[0] == 'y':
pdate = date.today()
# need to make some variable in main called posts that counts total posts
id = str(self.posts).zfill(3) # fills posts with up to 3 zeros
self.posts += 1
pid = 'p' + id
print(pid)
self.db.c.execute("""
INSERT INTO posts VALUES (?, ?, ?, ?, ?)
""", (pid, pdate, title, body, self.user)
)
self.db.commit()
print('You have posted "', title, '" to Tidder.')
makingpost = False
else:
print('Post deleted. Please type it again.')
return pid #returns ID of post being made, for answer() function
def searchposts(self):
searching = True
while searching: # As long as user is willing to search
print('What would you like to search? Enter any combination of words.')
entry = input('Enter your search here: ')
print('Searching...')
query = entry.split()
self.db.row_factory = sqlite3.Row # Might be unnecessary
for entry in query:
self.db.c.execute("""
SELECT DISTINCT p.pid, p.pdate, p.title, p.body, p.poster, COUNT(vno) as votes, COUNT(a.pid) as answers
FROM posts p
LEFT JOIN answers a ON a.qid = p.pid
LEFT JOIN votes v ON v.pid = p.pid
LEFT JOIN tags t ON t.pid = p.pid
WHERE p.title LIKE ?
OR p.body LIKE ?
OR t.tag LIKE ?
GROUP BY p.pid; """, ('%'+entry+'%', '%'+entry+'%', '%'+entry+'%')) # why is it displaying 2 answers what the flip
results = self.db.c.fetchall()
page = 0
selecting_post = True
lim_results = [results[x:x + 5] for x in range(0, len(results), 5)] # Breaks results into groups of 5
column = self.db.c.description
while selecting_post:
# Page decides what page of search results to look at, starts at 0
try:
"""Inserts names of columns at beginning of results"""
columns = []
for name in column: # Takes names of columns out of list
columns.append(name[0])
inter_columns = tuple(columns) # Turns list into tuple
if lim_results != []: # So IndexError still exists if there are no results
if lim_results[page][0] != inter_columns: # Only inserts column names once
lim_results[page].insert(0, inter_columns)
"""Prints results according to page, and allows selection"""
self.db.print_table(lim_results[page]) # Pretty prints results to console. (USING STOLEN CODE O.O)
print('Page', page+1, 'of', len(lim_results))
"""Had to move selection() to searchposts bc im dumb"""
print('To select a post, enter the post ID.')
print('To switch pages, type L (left) or R (right).')
print('To go back, type back.')
select = input('What would you like to do? > ').lower()
if select[0] == 'p' and len(select) == 4:
post = select
# Need to check the post selected is actually in the database
self.db.c.execute('SELECT pid FROM posts WHERE pid = ?', (post,))
exist = self.db.c.fetchall()
if exist:
print("\n")
self.postaction(post)
else:
print('The post you have selected does not exist. Please select a post.\n')
elif select == 'back':
selecting_post = False
elif select[0] == 'l':
if page >= 0:
page -= 1
else:
print('No more pages to be found.')
elif select[0] == 'r':
if page <= len(lim_results):
page += 1
else:
print('Invalid input. Try again.')
except IndexError:
print('Sorry, no results found.')
selecting_post = False
ask = input('Would you like to search again? (Y/N)').lower()
if ask[0] == 'n':
searching = False
def answer(self, post):
pid = self.makepost() # Returns ID of ANSWER post
try:
self.db.c.execute("""
INSERT INTO answers VALUES
(?, ?) """, (pid, post))
print('In response to', post + '.', '\n')
except sqlite3.IntegrityError as e:
print("Violates our protocol: ", e, '\n')
except Exception:
print("Some error occurred. Try again.", '\n')
def vote(self, post):
self.db.c.execute('SELECT MAX(vno) FROM votes') # as votes increments by one, this will return the latest vote
totalvotes = self.db.c.fetchall()
# Check if user already voted
vdate = date.today()
vote = int(totalvotes[0][0]) + 1 # Gets number from list of tuple, as it is formatted like [(number)]
self.db.c.execute('INSERT INTO votes VALUES (?, ?, ?, ?)', (post, vote, vdate, self.user))
print('Voted successfully!')
print('You are vote number', vote, '.\n')
def postaction(self, post):
deciding = True
privilegedUser = self.privileged()
while deciding: # showing the options to user
print('To vote on this post, type "v".')
print('To answer this post, type "a". ')
if privilegedUser: # only shows when the user is a privileged user
print('To mark as an acceptable answer for the question of the post,\n'+' if it is an answer, type "m".')
print('To give a badge for this post, type "b".')
print('To give tags on this post, type "t".')
print('To edit the post, type "edit"')
print('To go back to search results, type "back".')
# user choose an option
action = input('What would you like to do? >').lower()
if action == 'a':
self.answer(post)
elif action == 'v':
self.vote(post)
elif action == 'back':
deciding = False
self.searchposts()
elif privilegedUser:
if action == 'm':
self.markAcceptableAnswer(post)
elif action == 'b':
self.giveBadges(post)
elif action == 't':
self.giveTags(post)
elif action == 'edit':
self.editPost(post)
else:
print('Invalid action. Please try again.')
else:
print('Invalid action. Please try again.')
def markAcceptableAnswer(self, post):
"""
The post can have multiple situations while marking.
1. the question of the post already has a accepted answer
find the question from the post(answer)
check if the question has any accepted answer
if it has, then update
if error, then print error message
2. the question does not have any accepted answer
insert the qid, post into the questions database
:param post: the answer that we care about
:return: error message / update acceptable answer/ insert acceptable answer (if not present)
"""
# check if the post is an answer
self.db.c.execute('SELECT * FROM answers WHERE pid = ?;', (post,))
answer = self.db.c.fetchall() # should be zero if it is a question
if not answer:
print("Questions cannot be marked as accepted answers. Search again\n")
self.searchposts()
# Getting the question id using the answer post
self.db.c.execute('SELECT qid FROM answers WHERE pid = ?;', (post,))
questionid = self.db.c.fetchall()
# Getting the accepted answer for this question (if any)
self.db.c.execute('SELECT theaid FROM questions WHERE pid = ?;', (questionid[0][0],))
markedAnswer = self.db.c.fetchall() # # markedAnswer is an empty list if the post is still not marked
print("\n")
print("The question of the current selected answer:")
self.db.c.execute('SELECT * FROM posts WHERE pid = ?;', (questionid[0][0],))
results = self.db.c.fetchall()
self.printTable(results)
self.db.commit()
if markedAnswer:
# the question of the post already has a accepted answer
print("The current accepted answer: ")
self.db.c.execute('SELECT * FROM posts WHERE pid = ?;', (markedAnswer[0][0],))
results = self.db.c.fetchall()
self.printTable(results)
print("The answer you selected:")
self.db.c.execute('SELECT * FROM posts WHERE pid = ?;', (post,))
results = self.db.c.fetchall()
self.printTable(results)
self.db.commit()
print('The question already has an accepted answer. Do you want to change it? (Y/N)')
ask = self.replyYesNo()
if ask:
try:
self.db.c.execute("""UPDATE questions SET theaid = ? WHERE pid = ?;""", (post, questionid[0][0]))
print("Acccepted answer has been updated to: ", post)
except Exception:
print("Error occurred. Please try again later.")
print("\n")
self.db.commit()
self.postaction(post)
else: # user cancelled
print("Operation Cancelled")
print("\n")
self.postaction(post)
elif not markedAnswer: # does not have any selected answer
print("The answer you selected:")
self.db.c.execute('SELECT * FROM posts WHERE pid = ?;', (post,))
results = self.db.c.fetchall()
self.printTable(results)
self.db.commit()
print("Are you sure you want to make the changes?")
ask = self.replyYesNo()
if ask:
try:
self.db.c.execute("""INSERT INTO questions VALUES (?, ?);""", (questionid[0][0], post))
print("Accepted answer has been updated to: ", post)
self.db.commit()
except Exception:
print("Error occurred. Please try again later.")
print("\n")
self.postaction(post)
else: # user cancelled
print("Operation Cancelled")
print("\n")
self.postaction(post)
else:
print("Unknown error occurred. Please try again later.")
def replyYesNo(self):
key = True
ask = ''
while key:
ask = input().lower()
if ask == 'y' or ask == 'yes':
key = False
return True
elif ask == 'n' or ask == 'no':
key = False
return False
else:
print('Invalid response, please select (Y/N)')
continue
def printTable(self, results):
"""
Prints the table with rows in results
:param results: rows
:return: prints the rows
"""
try:
self.db.print_table(results) # Pretty prints results to console. (USING STOLEN CODE O.O)
except IndexError:
print('Sorry, no results found.')
def giveBadges(self, post):
"""
Privileged user can give badges to posts they like, when they select a post, they can write the badge
name that they want to give. If the badge is in our system, then update ubadges database with all
the necessary information but if it is not, give an error message and return the user back to
selection page.
:param post: the post selected
:return: (for successful attempt), ubadges is updated with the badge
"""
print("What badge would you like to give this post?")
badge = input()
# Check if the badge is present in our system.
self.db.c.execute("""SELECT *
FROM badges
WHERE bname = ?;""", (badge,))
badgeInSystem = self.db.c.fetchall()
if badgeInSystem: # not an empty list
# update ubadges
try:
self.db.c.execute("""
INSERT INTO ubadges VALUES
(?, ?, ?);
""", (self.user, date.today(), badge))
print("working on it...")
print("You gave a badge! Thanks for reviewing")
self.db.commit()
# return user back to postaction page.
print("\n") # for clarity
self.postaction(post)
except sqlite3.IntegrityError as e: # if duplicate data
print("This data already exists. Returning back to action page.\n")
self.postaction(post)
except Exception: # for any other problem
print("Something went wrong. Please try again.\n")
self.giveBadges(post)
else: # empty list, badge not present
print("Sorry, the badge is not in our system. Try again? (Y/N)")
answer = self.replyYesNo()
if answer: # user wants to try again
self.giveBadges(post)
else: # user gave up
print("\n") # for clarity
self.postaction(post)
def giveTags(self, post):
"""
privileged user can give tags to any posts that they have selected. And tags can be more than 1 or
take all the tags in, makes sure the tags are unique (case insensitive). Then update in the database.
:param post: the post selected
:return: updates information to database and print confirmation
"""
tags = []
index = 1
inputValue = ''
# Taking in user tags
print("Write 'end' when you are done with tags")
while inputValue != 'end':
print("Tag ", index, ":")
inputValue = input()
inputValue = inputValue.lower()
tags.append(inputValue)
index = index + 1
tags.remove("end") # "end" is not part of tag
tags = list(set(tags)) # keeping only unique values
print("working on it...")
if tags:
# inserting all the tags in database
for i in range(len(tags)):
try:
self.db.c.execute("""INSERT OR IGNORE INTO tags VALUES
(?, ?);
""", (post, tags[i]))
self.db.commit()
# for any error while inserting values in database
except Exception as e:
print("Something went wrong, please try again. Exception: \n", e)
self.giveTags(post)
# Operation done
print("Tags for this post has been updated.")
print("\n") # for clarity
self.postaction(post)
else: # If user press "end" without giving any input
print("Operation Cancelled")
print("\n") # for clarity
self.postaction(post)
def editPost(self, post):
"""
editPost takes a the post that user selected and gives the option to edit the title and/or the body
of the post.
:param post: the post selected
:return: update the title and/or body of the post, and output confirmation.
"""
print("If you do not want to change a part of the post, press enter to skip")
print("What do you want the new title to be?")
title = input()
print("Update new description")
body = input()
if title == '' and body == '': # If the user do not provide any info
print("Nothing to update. Do you want to perform any other operations?")
print("\n") # for clarity
self.postaction(post)
elif body == '': # user only wants to change the title
try:
self.db.c.execute("""
UPDATE posts
SET title = ?
WHERE pid = ?;
""", (title, post))
print("working on it...")
print("The title of the post is updated.")
print("\n") # for clarity
self.postaction(post)
except Exception as e:
print("Unknown error occurred. Please try again. Exception: \n", e)
self.editPost(post)
elif title == '': # user only wants to change the body
try:
self.db.c.execute("""
UPDATE posts
SET body = ?
WHERE pid = ?;
""", (body, post))
print("working on it...")
print("The description of the post is updated.")
print("\n") # for clarity
self.postaction(post)
except Exception as e:
print("Unknown error occurred. Please try again. Exception: \n", e)
self.editPost(post)
else: # user wants to change both
try:
self.db.c.execute("""
UPDATE posts
SET title = ?, body = ?
WHERE pid = ?;
""", (title, body, post))
print("working on it...")
print("The title and description of the post is updated.")
print("\n") # for clarity
self.postaction(post)
except Exception as e:
print("Unknown error occurred. Please try again. Exception: \n", e)
self.editPost(post)
def privileged(self):
"""
Check if user if a privileged user or not.
:return: True if privileged,
False otherwise.
"""
self.db.c.execute('Select * from privileged;')
allUserId = self.db.c.fetchall()
for users in allUserId:
for user in users:
if user == self.user:
return True
return False