def add_to_database(self, appstruct): """ Extract the fields from the colander validated dictionary, add to the database. """ # Get the user user = self.add_user_if_required() # Create a checkout with the current calibration data now = datetime.datetime.now() new_checkout = Checkout(serial=appstruct["serial"], timestamp=now) calib = Calibration(calibration_name="wavelength", coefficient_0=appstruct["coefficient_0"], coefficient_1=appstruct["coefficient_1"], coefficient_2=appstruct["coefficient_2"], coefficient_3=appstruct["coefficient_3"]) # Append this new calibration to the checkouts list of # calibrations new_checkout.calibrations.append(calib) # Append to that users' list of checkouts user.checkouts.append(new_checkout) DBSession.flush() # required to populate the id field return new_checkout.id
def checkout_delete(self): """ Show a confirmation screen for deleting a checkout. If the parameter confirm is present, actually delete and show the status. """ checkout_id = self.request.matchdict["checkout_id"] dbqry = DBSession.query(Checkout) checkout = dbqry.filter(Checkout.id == checkout_id).one() message = "Are you sure you want to delete checkout: %s" \ % checkout_id if "confirm" not in self.request.params: return {"checkout":checkout, "message":message} message = "Succesfully deleted checkout: %s" % checkout_id DBSession.delete(checkout) thumbs_glob = "cookbook/assets/img/thumbnails/%s_*.*" \ % checkout_id for filename in glob.glob(thumbs_glob): log.info("Delete file: %s", filename) os.remove(filename) return {"message":message}
def generate_calibration_report(self, appstruct, checkout_id): """ Use the generator object from the calibration report module to create a single page pdf. """ report = EmptyReport() report.serial = appstruct["serial"] report.coefficient_0 = appstruct["coefficient_0"] report.coefficient_1 = appstruct["coefficient_1"] report.coefficient_2 = appstruct["coefficient_2"] report.coefficient_3 = appstruct["coefficient_3"] pdf = WasatchSinglePage(report=report, return_blob=True) blob_data = pdf.return_blob() log.info("PDF report blob: %s", len(blob_data)) new_file = File(filename="Calibration_Report.pdf", file_data=blob_data) dbqry = DBSession.query(Checkout) checkout = dbqry.filter(Checkout.id == checkout_id).one() checkout.files.append(new_file) blob_data = pdf.return_thumbnail_blob() self.cache_blob(blob_data, checkout_id, "calibration_report_thumbnail.png") log.info("thumbnail report blob: %s", len(blob_data)) new_file = File(filename="calibration_report_thumbnail.png", file_data=blob_data) dbqry = DBSession.query(Checkout) checkout = dbqry.filter(Checkout.id == checkout_id).one() checkout.files.append(new_file)
def connect_database(self): """ Use sqlalchemy to connect directly to the database file on disk. """ from sqlalchemy import create_engine engine = create_engine("sqlite:///config/cookbook.sqlite") DBSession.configure(bind=engine) Base.metadata.create_all(engine) return DBSession
def main(argv=sys.argv): """ Create a completely empty database.""" if len(argv) < 2: usage(argv) config_uri = argv[1] options = parse_vars(argv[2:]) setup_logging(config_uri) settings = get_appsettings(config_uri, options=options) engine = engine_from_config(settings, "sqlalchemy.") DBSession.configure(bind=engine) Base.metadata.create_all(engine)
def main(global_config, **settings): """ This function returns a Pyramid WSGI application. """ engine = engine_from_config(settings, "sqlalchemy.") DBSession.configure(bind=engine) Base.metadata.bind = engine auth_tkt_pol = AuthTktAuthenticationPolicy authentication_policy = auth_tkt_pol(auth_policy_secret, callback=access_verifier, hashalg='sha512') authorization_policy = ACLAuthorizationPolicy() config = Configurator(settings=settings, root_factory="cookbook.models.RootFactory", authentication_policy=authentication_policy, authorization_policy=authorization_policy) config.include("pyramid_chameleon") # Static assets include thumbnails, turn off caching to ensure they # are reloaded in a timely fashion config.add_static_view("assets", "assets", cache_max_age=1) config.add_route("file_add", "/file_add/{checkout_id}") config.add_route("file_view", "/file_view/{checkout_id}/{filename}") config.add_route("checkout_list", "/checkout_list/") config.add_route("checkout_add", "/checkout_add/") config.add_route("checkout_view", "/checkout/{checkout_id}") config.add_route("checkout_delete", "/checkout_delete/{checkout_id}") config.add_route("login", "/login/google") config.add_route("logout", "/logout/google") config.add_route("user_view", "/user_view/") config.add_route("analyze_view", "/analyze/") config.add_route("analyze_long_term_view", "/analyze_long_term/") config.add_route("serial_view", "/{serial}") config.add_route("home_redirect", "/") config.scan("cookbook.views") return config.make_wsgi_app()
def explode_work_ticket(self, appstruct, checkout_id): """ If work_ticket in the filename, create an exploded mosaic thumbnail and add that to the database. """ lower_name = appstruct["file_upload"]["filename"].lower() if "work_ticket" not in lower_name \ or ".pdf" not in lower_name: return file_pointer = appstruct["file_upload"]["fp"] file_pointer.seek(0) thumg = ThumbnailGenerator(blob=file_pointer.read()) png_img = thumg.mosaic_thumbnail() thumbnail_name = "mosaic_work_ticket_thumbnail.png" new_file = File(filename=thumbnail_name, file_data=png_img) log.info("assign: %s to %s", new_file.filename, checkout_id) dbqry = DBSession.query(Checkout) checkout = dbqry.filter(Checkout.id == checkout_id).one() checkout.files.append(new_file) # Save the thumbnail to disk self.cache_blob(png_img, checkout_id, "mosaic_work_ticket_thumbnail.png")
def file_add(self): """ Expect a valid checkout id, add a file to the file system and store retrieval values in database. """ # require a known checkout id checkout_id = self.request.matchdict["checkout_id"] dbqry = DBSession.query(Checkout) checkout = dbqry.filter(Checkout.id == checkout_id).one() form = Form(NewFileSchema(), buttons=("submit",)) if "submit" in self.request.POST: log.info("File submit: %s", self.request.POST) controls = self.request.POST.items() try: appstruct = form.validate(controls) self.assign_filename_if_selected(appstruct) chk_id = self.file_add_to_database(appstruct) self.explode_work_ticket(appstruct, chk_id) self.cache_thumbnails(appstruct, chk_id) location = self.request.route_url("checkout_view", checkout_id=chk_id) return HTTPFound(location=location) except ValidationFailure as exc: log.warn("File Validation failure") checkout = {"serial":"invalid", "id":"invalid", "timestamp":"invalid"} return {"form":exc.render(), "checkout":checkout} return {"form":form.render(), "checkout":checkout}
def add_user_if_required(self): """ Try and find that user in the database, add it if required. Requires the user to be authenticated. """ useremail = self.request.authenticated_userid dbqry = DBSession.query(User) checkout = dbqry.filter(User.fullemail == useremail).first() if checkout is None: log.warn("User does not exist, adding: %s", useremail) new_user = User(fullemail=useremail, fullname="testname") DBSession.add(new_user) checkout = dbqry.filter(User.fullemail == useremail).first() return checkout
def build_stats(self): """ Classify and count checkouts based on their serial number. """ dbqry = DBSession.query(Checkout).filter cobra = dbqry(Checkout.serial.like("C-%")).count() stroker_785l = dbqry(Checkout.serial.like("S785L%")).count() stroker_785c = dbqry(Checkout.serial.like("S785C%")).count() ventana = dbqry(Checkout.serial.like("V%")).count() # Other is total count - sum of all found groups db_total = DBSession.query(Checkout).count() other = db_total - (cobra + stroker_785l + ventana + stroker_785c) return dict(cobra=cobra, stroker_785l=stroker_785l, other=other, stroker_785c=stroker_785c, ventana=ventana, db_total=db_total)
def file_add_to_database(self, appstruct): """ Write the file upload to the database. Append it to the list of files for the checkout. """ #log.info("full appstruct: %s", appstruct) file_pointer = appstruct["file_upload"]["fp"] file_pointer.seek(0) filename = appstruct["file_upload"]["filename"] filename = self.strip_test_delimiters(filename) new_file = File(filename=filename, file_data=file_pointer.read()) #log.info("Obj: %r", file_pointer) log.info("assign: %s", new_file.filename) checkout_id = self.request.matchdict["checkout_id"] dbqry = DBSession.query(Checkout) checkout = dbqry.filter(Checkout.id == checkout_id).one() checkout.files.append(new_file) DBSession.flush() #required to get checkout id return checkout.id
def analyze_long_term_view(self): """ All statistics from the db """ dbqry = DBSession.query(Checkout).filter # Gather a list of the previous six months including year, use # mktime to roll over the year where applicable. From: # http://stackoverflow.com/questions/6576187/\ # get-year-month-for-the-last-x-months month_history = 32 now = time.localtime() month_list = [] month_names = [] for month in range(month_history): make_time = time.mktime((now.tm_year, now.tm_mon - month, 1, 0, 0, 0, 0, 0, 0) ) new_time = time.localtime(make_time) # Convert the month to two digit loc_mon = "%s" % new_time.tm_mon if len(loc_mon) == 1: loc_mon = "0%s" % loc_mon # Use a LIKE query on the timestamp value time_str = "%s-%s%%" % (new_time.tm_year, loc_mon) count = dbqry(Checkout.timestamp.like(time_str)).count() month_list.insert(0, str(count)) month_names.insert(0, calendar.month_name[new_time.tm_mon]) # Create the javascript text line month_string = ",".join(month_list) month_data = "data : [%s]," % month_string # Javascript axis label month_words = "\", \"".join(month_names) month_labels = "labels: [\"%s\",]," % month_words # Build the statistics by class classes = self.build_stats() prefix_groups = self.build_prefix_groups() return dict(month_data=month_data, month_labels=month_labels, classes=classes, prefix_groups=prefix_groups, )
def generate_qr_label(self, appstruct, checkout_id): """ Use the stickercode generation code inline from the StickerCode project. Generate a temporary qr label on disk, then load it into a db blob. """ lbl = QL700Label(domain="http://waspho.com", serial=appstruct["serial"], return_blob=True) blob_data = lbl.return_blob() self.cache_blob(blob_data, checkout_id, "qr_label.png") new_file = File(filename="qr_label.png", file_data=blob_data) log.info("QR Llabel blob: %s", len(blob_data)) dbqry = DBSession.query(Checkout) checkout = dbqry.filter(Checkout.id == checkout_id).one() checkout.files.append(new_file)
def serial_view(self): """ Get the most recent checkout with the specified serial number. Send to view by checkout to return desired info. """ serial = self.request.matchdict["serial"] log.info("Find: %s", serial) dbqry = DBSession.query(Checkout) order_by = dbqry.order_by(Checkout.timestamp.desc()) last_id = order_by.filter(Checkout.serial == serial).first() if last_id is None: log.info("Can't find: %s", serial) return HTTPNotFound() log.info("Checkout id assigned: %s for %s", last_id.id, serial) self.request.matchdict["checkout_id"] = last_id.id return self.checkout_view()
def file_view(self): """ Find a file matching the checkout id and filename passed into matchdict. Otherwise return failures. """ # require a known checkout id checkout_id = self.request.matchdict["checkout_id"] dbqry = DBSession.query(Checkout) checkout = dbqry.filter(Checkout.id == checkout_id).one() filename = self.request.matchdict["filename"] #log.warn("Find: %s, %s as %s", checkout_id, filename, #self.request.authenticated_userid) #log.info("Params: %s", self.request.params) file_data = self.database_or_placeholder(checkout, filename) file_data = self.resize_if_params(file_data) return self.build_file_response(file_data, filename)
def insert_file(self, checkout_id, full_name, short_name): """ Open the file on disk, write the contents to the database. """ log.debug("Insert %s into checkout: %s", full_name, checkout_id) if not os.path.exists(full_name): log.warn("%s file does not exist", full_name) return file_pointer = open(full_name) file_pointer.seek(0) with transaction.manager: new_file = File(filename=short_name, file_data=file_pointer.read()) dbqry = DBSession.query(Checkout) checkout = dbqry.filter(Checkout.id == checkout_id).one() checkout.files.append(new_file) log.debug("Added %s to checkout: %s", short_name, checkout_id)
def build_prefix_groups(self): """ Create a list of 1-N letter prefixes of all the serial numbers in the database. This provides a primitive breakdown of device classes. """ dbqry = DBSession.query(Checkout).all() from collections import defaultdict prefixes = defaultdict(int) prefixes = {} for item in dbqry: start = item.serial[0:2] if start in prefixes: prefixes[start] += 1 else: prefixes[start] = 1 print "All group prefixes: %s" % prefixes return prefixes
def checkout_list(self): """ Return entire list of checkouts from the database. If page parameter is specified, show just a slice of the results. """ dbqry = DBSession.query(Checkout).order_by checkouts = dbqry(Checkout.timestamp.desc()).all() # If page not specified, set range to full extent page_num = 1 if "page" not in self.request.params: start = 0 stop = len(checkouts) else: page_length = 10 page_num = int(self.request.params["page"]) start = page_length * (page_num-1) stop = start + page_length # Accept the goodness that a slice out of range on a query # return does not throw an exception, it returns zero devices or # the last N in the list checkouts = checkouts[start:stop] return {"checkouts":checkouts}
def checkout_view(self): """ Build a dictionary of template-expected values of the checkout, user and file data model. """ checkout_id = self.request.matchdict["checkout_id"] dbqry = DBSession.query(Checkout) checkout = dbqry.filter(Checkout.id == checkout_id).first() log.info("View checkout %s", checkout.serial) allow_files = [] for item in checkout.files: #log.info("Checkout file: %s", item.filename) if self.filename_allowed(item.filename): allow_files.append(item) else: log.warn("Not showing file: %s", item.filename) link_files = {} bad_names = ["high_camera_image", "low_camera_image", "qr_label", "Calibration_Report", "calibration_report_thumbnail", "work_ticket",] for item in allow_files: found = 0 for check_str in bad_names: if check_str in item.filename: #log.info("Not listing file %s", item.filename) found += 1 if found == 0: link_files[item.filename] = len(item.file_data) return {"checkout":checkout, "files":allow_files, "link_files":link_files}