# Path: passwordtype.py
# def hashpassword(password):
#     return bcrypt.hashpw(encode(password), bcrypt.gensalt())
# 
# def encode(s):
#     return s.encode('utf8')
# 
# Path: library.py
# def csrf_protect():
# def generate_csrf_token():
# def logout_user():
# def login_required(test):
#     def wrap(*args, **kwargs):
# def inject_sitename():
# def login():
# def logout():
# def main():
# def admin():
# def librarian(rlid=None):
# def adduser():
# def deleteuser(username):
# def addrecread():
# def remrecread(rlid):
# def changeSticky(rlid):
# def profile(uname):
# def edit_profile(uname):
# def valid_image_file(image_file):
# def upload_picture(uname):
# def contact(uname):
# def contact_status(PCID):
# def is_valid_password(s):
# def changepassword():
# def reset_request():
# def reset_password():
# def publish():
#     ISBN = request.form['ISBN']
# 
# Path: models.py
# class Staff(Base):
#     __tablename__ = 'staff'
# 
#     username = Column(String, primary_key=True)
#     password = Column(PasswordType)
#     f_name = Column(String)
#     l_name = Column(String)
#     phonenumber = Column(String)
#     emailaddress = Column(String, unique=True)
# 
#     bio = Column(Text, default='')
#     email = Column(Boolean, default=True)
#     phone = Column(Boolean, default=False)
#     chat = Column(Boolean, default=False)
#     irl = Column(Boolean, default=False)
# 
#     interests = Column(Text, default='')
# 
#     patron_contacts = relationship('PatronContact',
#                                    cascade='all, delete-orphan',
#                                    backref=backref('staff',
#                                                    uselist=False))
# 
#     def __getitem__(self, attr):
#         return getattr(self, attr)
# 
#     @property
#     def category_list(self):
#         return set([item.category for item in self.readinglist])
# 
#     def profile_path(self):
#         from library import app
#         uploadsdir = os.path.join(app.static_folder, 'uploads')
# 
#         # uuid4 regex
#         # https://stackoverflow.com/a/18359032
#         fnre = re.compile(r'(.+)-[\da-f]{8}-[\da-f]{4}-4[\da-f]{3}-[89ab][\da-f]{3}-[\da-f]{12}\.jpg')
# 
#         for fn in os.listdir(uploadsdir):
#             match = fnre.match(fn)
#             if match:
#                 fnusername = match.groups(1)[0]
#             else:
#                 fnusername, _ = os.path.splitext(fn)
#             if fnusername == self.username:
#                 pic_file_name = 'uploads/%s' % fn
#                 break
#         else:
#             pic_file_name = 'uploads/anon.jpg'
# 
#         return pic_file_name
# 
#     def full_name(self):
#         return str(self.f_name) + ' ' + str(self.l_name)


import re
import argparse
import bcrypt
import os, sys
from sqlalchemy.sql import text
from passwordtype import hashpassword, encode
from library import app, db
from models import Staff
    return re.match(r'\$[0-9a-z]+\$\d+\$[0-9A-Za-z.\\]+', s)

def update_passwords():
    """
    Update the plain-text passwords to bcrypt. Checks to see if already hashed,
    however admin should check if this needs to be run first.
    """
    with app.app_context():
        conn = db.session.connection()

        for staff in Staff.query.all():
            plaintext = staff.password.hashed

            # Make some attempt not to hash already hashed passwords
            if ishashed(plaintext):
                continue

            hashed = hashpassword(plaintext)

            # Have to sneak around the Staff class to get at the literal database value.
            sql = text('update staff set password = :hashed where username = :username')
            conn.execute(sql, hashed=hashed, username=staff.username)

        db.session.commit()

def main():
    argparser = argparse.ArgumentParser(description=update_passwords.__doc__)
    argparser.add_argument('--echo', action='store_true', help='Echo SQL commands.')
    args = argparser.parse_args()


# Path: passwordtype.py
# def hashpassword(password):
#     return bcrypt.hashpw(encode(password), bcrypt.gensalt())
# 
# def encode(s):
#     return s.encode('utf8')
# 
# Path: library.py
# def csrf_protect():
# def generate_csrf_token():
# def logout_user():
# def login_required(test):
#     def wrap(*args, **kwargs):
# def inject_sitename():
# def login():
# def logout():
# def main():
# def admin():
# def librarian(rlid=None):
# def adduser():
# def deleteuser(username):
# def addrecread():
# def remrecread(rlid):
# def changeSticky(rlid):
# def profile(uname):
# def edit_profile(uname):
# def valid_image_file(image_file):
# def upload_picture(uname):
# def contact(uname):
# def contact_status(PCID):
# def is_valid_password(s):
# def changepassword():
# def reset_request():
# def reset_password():
# def publish():
#     ISBN = request.form['ISBN']
# 
# Path: models.py
# class Staff(Base):
#     __tablename__ = 'staff'
# 
#     username = Column(String, primary_key=True)
#     password = Column(PasswordType)
#     f_name = Column(String)
#     l_name = Column(String)
#     phonenumber = Column(String)
#     emailaddress = Column(String, unique=True)
# 
#     bio = Column(Text, default='')
#     email = Column(Boolean, default=True)
#     phone = Column(Boolean, default=False)
#     chat = Column(Boolean, default=False)
#     irl = Column(Boolean, default=False)
# 
#     interests = Column(Text, default='')
# 
#     patron_contacts = relationship('PatronContact',
#                                    cascade='all, delete-orphan',
#                                    backref=backref('staff',
#                                                    uselist=False))
# 
#     def __getitem__(self, attr):
#         return getattr(self, attr)
# 
#     @property
#     def category_list(self):
#         return set([item.category for item in self.readinglist])
# 
#     def profile_path(self):
#         from library import app
#         uploadsdir = os.path.join(app.static_folder, 'uploads')
# 
#         # uuid4 regex
#         # https://stackoverflow.com/a/18359032
#         fnre = re.compile(r'(.+)-[\da-f]{8}-[\da-f]{4}-4[\da-f]{3}-[89ab][\da-f]{3}-[\da-f]{12}\.jpg')
# 
#         for fn in os.listdir(uploadsdir):
#             match = fnre.match(fn)
#             if match:
#                 fnusername = match.groups(1)[0]
#             else:
#                 fnusername, _ = os.path.splitext(fn)
#             if fnusername == self.username:
#                 pic_file_name = 'uploads/%s' % fn
#                 break
#         else:
#             pic_file_name = 'uploads/anon.jpg'
# 
#         return pic_file_name
# 
#     def full_name(self):
#         return str(self.f_name) + ' ' + str(self.l_name)


# Path: migration/01_hashpasswords.py
import re
import argparse
import bcrypt
import os, sys
from sqlalchemy.sql import text
from passwordtype import hashpassword, encode
from library import app, db
from models import Staff

    return re.match(r'\$[0-9a-z]+\$\d+\$[0-9A-Za-z.\\]+', s)

def update_passwords():
    """
    Update the plain-text passwords to bcrypt. Checks to see if already hashed,
    however admin should check if this needs to be run first.
    """
    with app.app_context():
        conn = db.session.connection()

        for staff in Staff.query.all():
            plaintext = staff.password.hashed

            # Make some attempt not to hash already hashed passwords
            if ishashed(plaintext):
                continue

            hashed = hashpassword(plaintext)

            # Have to sneak around the Staff class to get at the literal database value.
            sql = text('update staff set password = :hashed where username = :username')
            conn.execute(sql, hashed=hashed, username=staff.username)

        db.session.commit()

def main():
    argparser = argparse.ArgumentParser(description=update_passwords.__doc__)
    argparser.add_argument('--echo', action='store_true', help='Echo SQL commands.')
    args = argparser.parse_args()


    if not any((hashpassword, app, db, Staff)):