예제 #1
0
    def view_files(self):
        self.require_verification()
        form = Form(self.request, schema=forms.UploadFileSchema)
        with utils.db_session(self.dbmaker) as session:
            user = session.query(User).filter(User.username==self.username).first()
            current_upload_size = sum([f.size for f in user.files])
            username = user.username
            owned_files = dict()
            shared_files = dict()
            for f in user.files:
                shared_with = [k.user.username for k in f.keys]
                owned_file = dict(shared=shared_with, uploaded_at=f.uploaded_at, size=f.size)
                owned_files[f.name] = owned_file
                shared_files[f.name] = dict(size=f.size, owner=f.owner.username)
            sharable_users = session.query(User).filter(User.sharable==True)
            sharable_users = sharable_users.filter(User.username!=self.username).all()
            sharable_users = [u.username for u in sharable_users]

        return dict(
            current_upload_size=current_upload_size,
            form=FormRenderer(form),
            username=username,
            uploaded_files=owned_files,
            sharable_users=sharable_users,
            shared_files=shared_files
        )
예제 #2
0
 def require_key(self, errmsg=u'you must first create a key to do that'):
     self.require_verification()
     with utils.db_session(self.dbmaker) as session:
         user = session.query(User).filter(User.username==self.username).first()
         if not user.keys:
             self.request.session.flash(errmsg)
             raise HTTPFound(location=self.request.route_url('keys'))
예제 #3
0
파일: views.py 프로젝트: derekzchu/planner
def get_work_order(work_id = None, task_id = None):
    """
    Get a specified work order

    @return request work orders
    """

    ret = []
    with utils.db_session() as session:
        if work_id:
            query_res = session.query(models.WorkOrder).get(work_id)
            if not query_res:
                raise HTTPError(404, 'Work Order not found')
            ret = query_res.as_dict()
        elif task_id:
            query_res = session.query(models.WorkOrder)\
                .filter(models.Task.id == task_id).join(models.Task)
            for result in query_res:
                link = url_for('get_work_order', work_id = result.id)
                ret.append(result.as_dict(link = link))
        else:
            query_res = session.query(models.WorkOrder).all()
            for result in query_res:
                link = url_for('get_work_order', work_id = result.id)
                ret.append(result.as_dict(link = link))

    return json.dumps(ret)
예제 #4
0
파일: views.py 프로젝트: derekzchu/planner
def get_plans(plan_id = None):
    """
    Get all the plans.
    @param plan_id is pk of the plan table

    @return plans
    """
    ret = None
    with utils.db_session() as session:
        if plan_id:
            query_res = session.query(models.Plan).get(plan_id)
            if not query_res:
                raise HTTPError(404, 'Plan not found')

            task_base = url_for('get_tasks')
            ret = query_res.as_dict(task_base = task_base)

        else:
            query_res = session.query(models.Plan).all()
            ret = []
            for result in query_res:
                link = url_for('get_plans', plan_id = result.id)
                ret.append(result.as_dict(link = link))

    return json.dumps(ret)
예제 #5
0
 def require_verification(self, errmsg=u'Account must be verified to do that'):
     self.require_login()
     with utils.db_session(self.dbmaker) as session:
         user = session.query(User).filter(User.username==self.username).first()
         if user.verified_at is None:
             self.request.session.flash(errmsg)
             raise HTTPFound(location=self.request.route_url('user', userid=self.username))
예제 #6
0
파일: views.py 프로젝트: derekzchu/planner
def update_tasks(task_id):
    """
    Updates a task. The follow operations are allowed by the client:
    1. Reparent the task's plan
    2. Change the product id iff the task has 0 workorders
    
    @param task_id pk
    @return success status
    """

    content = request.get_json()
    new_plan_id = content.get('plan_id', None)
    new_product_id = content.get('product_id', None)
    new_target_quantity = content.get('target_quantity', None)

    if new_target_quantity and (not isinstance(new_target_quantity, int)
                                or new_target_quantity <= 0):
        raise HTTPError(400, 'Invalid target quantity')

    with utils.db_session() as session:
        task = session.query(models.Task).get(task_id)
        if not task:
            raise HTTPError(404, 'Task not found')

        if new_plan_id:
            plan = session.query(models.Plan).get(new_plan_id)
            if not plan:
                raise HTTPError(404, 'Target plan not found')

            task.plan_id = new_plan_id
            session.flush()

        else:
            if new_product_id:
                #check if existing work orders
                if len(task.work_order) > 0:
                    raise HTTPError(403, 'Task has existing work orders. Cannot alter product')

                task.product_id = new_product_id
                new_target_quantity = task.target_quantity

            if new_target_quantity:
                if not new_product_id:
                    new_product_id = task.product_id

                #check if there's enough inventory
                available_inventory = session.query(models.Inventory)\
                    .get(new_product_id)
                
                if not available_inventory or \
                        available_inventory.quantity < new_target_quantity :
                    raise HTTPError(403, 'Task has Insufficient product quantity')

                task.target_quantity = new_target_quantity

            session.flush()

        link = url_for('get_tasks', tasks_id = task_id)
        ret = task.as_dict(link = link)
        return json.dumps(ret)
예제 #7
0
파일: views.py 프로젝트: derekzchu/planner
def get_tasks(plan_id = None, task_id = None):
    """
    Get tasks. Can retrieve a single task, all tasks, or all tasks given
    a plan_id. If plan_id specified, return a join of plan and tasks of that
    plan.

    @param: task_id pk
    @param: plan_id pk

    @returns list of task/tasks
    """
    ret = []
    with utils.db_session() as session:
        if task_id:
            query_res = session.query(models.Task).get(task_id)
            if not query_res:
                raise HTTPError(404, 'Task id not found')

            ret = query_res.as_dict(include_wo = True)

        elif plan_id:
            query_res = session.query(models.Plan, models.Task)\
                .filter(models.Plan.id == plan_id).join(models.Task)

            for plan_res, result in query_res:
                link = url_for('get_tasks', task_id = result.id)
                ret.append(result.as_dict(include_wo = True, link = link))

        else:
            query_res = session.query(models.Task).all()
            for result in query_res:
                link = url_for('get_tasks', task_id = result.id)
                ret.append(result.as_dict(include_wo = True, link = link))

    return json.dumps(ret)
예제 #8
0
 def delete_file(self):
     query_file = os.path.join(self.storage_dir, self.username, self.filename)
     with utils.db_session(self.dbmaker) as session:
         f = session.query(File).filter(File.name==self.filename).first()
         session.delete(f)
     os.remove(query_file)
     self.request.session.flash(u'successfully deleted file: %s.' % (self.filename, ))
     return HTTPFound(location=self.request.route_url('view_files'))
예제 #9
0
 def share_file(self):
     form = Form(self.request, schema=forms.PassphraseSchema)
     if 'form.submitted' in self.request.POST and form.validate():
         passphrase = form.data['passphrase']
         query_file = os.path.join(self.storage_dir, self.username, self.filename)
         share_user = self.request.params['share_user']
         with utils.db_session(self.dbmaker) as session:
             owner = session.query(User).filter(User.username==self.username).one()
             f = session.query(File).filter(File.name==self.filename).one()
             u = session.query(User).filter(User.username==share_user).first()
             if u is None:
                 del f.shared_users[:]
             else:
                 for key in u.keys:
                     f.keys.append(key)
             session.add(f)
             owner_pubs = [k.public_key for k in owner.keys]
             owner_privs = [k.private_key for k in owner.keys]
             recipients = owner_pubs + [k.public_key for k in f.keys]
             with open(query_file, 'rb') as o:
                 data = o.read()
             decrypted = utils.decrypt(data, owner_privs, owner_pubs, passwd)
             with tempfile.NamedTemporaryFile() as tmp:
                 tmp.write(decrypted)
                 tmp.flush()
                 tmp.seek(0)
                 encrypted = utils.encrypt(tmp, recipients)
             tmp = tempfile.NamedTemporaryFile(dir=self.storage_dir, delete=False)
             tmp.write(encrypted)
             os.rename(tmp.name, query_file)
         self.request.session.flash(
             u'successfully shared file: %s with user %s' % (self.filename, share_user)
         )
         return HTTPFound(location=self.request.route_url('view_files'))
     with utils.db_session(self.dbmaker) as session:
         sharable_users = session.query(User).filter(User.sharable==True)
         sharable_users = sharable_users.filter(User.username!=self.username).all()
         sharable_users = [u.username for u in sharable_users]
     return dict(
         username=self.username,
         filename=self.filename,
         sharable_users=sharable_users
     )
예제 #10
0
파일: views.py 프로젝트: derekzchu/planner
def create_work_order(task_id):
    """
    Creates a new work order
    @param: task_id (pk)
    @body: json target_quantity

    @return work order    
    """

    ret = []
    content = request.get_json()
    target_quantity = content.get('target_quantity', None)
    if not isinstance(target_quantity, int) and target_quantity <= 0:
        raise HTTPError(400, 'Invalid parameters to work order')

    with utils.db_session() as session:
        total_work = func.sum(models.WorkOrder.target_quantity)\
            .label('total_wo_quantity')

        query_res = session.query(\
            models.Task, total_work)\
            .outerjoin(models.WorkOrder)\
            .filter(models.Task.id == task_id)
#        query_res = session.query(\
#            models.Task.target_quantity, models.Task.status, total_work)\
#            .outerjoin(models.WorkOrder)\
#            .filter(models.Task.id == task_id)

        for result in query_res:
            task, total_work = result
#            task_target_quantity, task_status, total_work = result
        if not total_work:
            total_work = 0

        if not task:
            raise HTTPError(404, 'Task not found')

        if task.get_status() == Status.COMPLETED:
            raise HTTPError(403, 'Task is already completed. Cannot add new work order')

        if target_quantity + total_work > task.target_quantity:
            raise HTTPError(403, 'New work order quantity greater than task total quantity')
        
        new_wo = models.WorkOrder()
        new_wo.target_quantity = target_quantity
        new_wo.task_id = task_id

        session.add(new_wo)
        session.flush()

        link = url_for('get_work_order', work_id = new_wo.id)
        ret = new_wo.as_dict(link = link)
    return json.dumps(ret)
예제 #11
0
 def unshare_file(self):
     query_file = os.path.join(self.storage_dir, self.username, self.filename)
     with utils.db_session(self.dbmaker) as session:
         f = session.query(File).filter(File.name==self.filename).first()
         u = session.query(User).filter(User.username==self.unshare_user).first()
         for key in u.keys:
             if key in f.keys:
                 f.keys.remove(key)
         session.add(f)
     self.request.session.flash(
         u'no longer sharing file: %s with user: %s' % (self.filename, self.unshare_user)
     )
     return HTTPFound(location=self.request.route_url('view_files'))
예제 #12
0
파일: views.py 프로젝트: derekzchu/planner
def delete_work_order(work_id):
    """
    Delete a specified work order. Can only delete if work order has
    status: NOTSTARTED
    """

    with utils.db_session() as session:
        work_order = session.query(models.WorkOrder).get(work_id)
        if work_order:
            if work_order.status != Status.NOTSTARTED:
                raise HTTPError(403, 'Cannot delete an active work order')

            session.delete(work_order)

    return json.dumps({})
예제 #13
0
파일: views.py 프로젝트: derekzchu/planner
def delete_plans(plan_id):
    """
    Deletes a plan if specified plan has no tasks
    """
    with utils.db_session() as session:
        plan = session.query(models.Plan).get(plan_id)
        if plan:
#            num_tasks = session.query(models.Task)\
#                .filter(models.Task.plan_id == plan_id).count()
#            if num_tasks > 0:

            if len(plan.tasks) > 0:
                raise HTTPError(403, 'Cannot delete plan with tasks')

            session.delete(plan)
    return json.dumps({'Success': True})
예제 #14
0
파일: views.py 프로젝트: derekzchu/planner
def delete_task(task_id):
    """
    Deletes a specified task

    @param task_id pk
    @return success
    """

    with utils.db_session() as session:
        task = session.query(models.Task).get(task_id)
        if task:
            if task.get_status() != Status.NOTSTARTED:
                raise HTTPError(403, 'Task already started. Cannot delete active task')

            session.delete(task)

    return json.dumps({})
예제 #15
0
파일: views.py 프로젝트: derekzchu/planner
def create_plan():
     """
     create a new plan

     @return plan dict
     """
     content = request.get_json()
     name = content.get('name', None)
     if name is None:
         raise HTTPError(400, 'Plan is missing a name')

     with utils.db_session() as session:
         new_plan = models.Plan(name)
         session.add(new_plan)
         session.flush()

         link = url_for('get_plans', plan_id = new_plan.id)
         ret = new_plan.as_dict(link = link)
     return json.dumps(ret)
예제 #16
0
 def view_file(self):
     form = Form(self.request, schema=forms.PassphraseSchema)
     if 'form.submitted' in self.request.POST and form.validate():
         with utils.db_session(self.dbmaker) as session:
             user = session.query(User).filter(User.username==self.username).first()
             f = session.query(File).filter(File.name==self.filename).first()
             proper_key = [k for k in f.keys if k.user.username == user.username]
             logger.info('owner: %s files: %s keys: %s', f.owner, user.files, f.keys)
             if f.owner != user.username and len(proper_key) == 0:
                 self.request.session.flash(u'File not shared with you. are you a bad actor?')
                 return HTTPFound(location=self.request.route_url('home'))
             privs = []
             pubs = []
             for k in proper_key:
                 privs.append(k.private_key)
                 pubs.append(k.public_key)
             query_file = os.path.join(self.storage_dir, f.owner.username, self.filename)
         if not os.path.isfile(query_file):
             return HTTPNotFound("file %s is not a thinger" % (self.filename, ))
         content_type, encoding = mimetypes.guess_type(query_file)
         with open(query_file, 'rb') as o:
             encrypted = o.read()
             decrypted = utils.decrypt(encrypted, privs, pubs, form.data['passphrase']) 
         with utils.tmpdir() as tmpd:
             tmp = os.path.join(tmpd, self.filename)
             with open(tmp, 'wb') as tmpf:
                 tmpf.write(decrypted)
                 tmpf.flush()
                 response = FileResponse(
                     tmp,
                     request=self.request,
                     content_type=content_type,
                     content_encoding=encoding
                 )
                 return response
     return dict(
         form=FormRenderer(form),
         username=self.username,
         filename=self.filename
     )
예제 #17
0
파일: views.py 프로젝트: derekzchu/planner
def get_inventory(inv_id = None):
    """
    Get the central inventory
    @param inv_id is the pk of the inventory item

    @return inventory
    """
    ret = None
    with utils.db_session() as session:
        if inv_id:
            query_res = session.query(models.Inventory).get(inv_id)
            if not query_res:
                raise HTTPError(404, 'Inventory not found')
            ret = query_res.as_dict()
        else:
            query_res = session.query(models.Inventory).all()
            ret = []
            for result in query_res:
                link = url_for('get_inventory', inv_id = result.id)
                ret.append(result.as_dict(link = link))

    return json.dumps(ret)
예제 #18
0
    def manage_file(self):
        with utils.db_session(self.dbmaker) as session:
            user = session.query(User).filter(User.username==self.username).first()
            f = session.query(File).filter(File.name==self.filename).first()
            username = user.username
            size = f.size
            uploaded_at = f.uploaded_at

            sharable_users = session.query(User).filter(User.sharable==True)
            sharable_users = sharable_users.filter(User.username!=self.username).all()
            sharable_users = [u.username for u in sharable_users]

            shared_with = ', '.join([k.user.username for k in f.keys])

        return dict(
            username=username,
            filename=self.filename,
            uploaded_at=uploaded_at,
            size=size,
            sharable_users=sharable_users,
            shared_with=shared_with
        )
예제 #19
0
    def upload_file(self):
        self.require_key()
        with utils.db_session(self.dbmaker) as session:
            user = session.query(User).filter(User.username==self.username).first()

            if 'uploaded_file' in self.request.POST and form.validate():
                f = form.data['uploaded_file']
                name = f['filename']
                size = f['size']
                self.request.session.flash(u'successfully uploaded file %s.' % (name, ))
                pubs = []
                for key in user.keys:
                    pubs.append(key.public_key)
                encrypted = utils.encrypt(f['file'], pubs)
                name = utils.store_file(encrypted, name, user.username, self.storage_dir)
                fileobj = File(name, size, user.id)
                fileobj.owner = user
                for key in user.keys:
                    fileobj.keys.append(key)
                user.files.append(fileobj)
                session.add(user)

        return HTTPFound(location=self.request.route_url('view_files'))
예제 #20
0
파일: views.py 프로젝트: derekzchu/planner
def create_task(plan_id):
    """
    Create a task
    @param: plan_id
    @body: json object with prod_id, and quantity

    @returns: task resource if successful
    """
    content = request.get_json()
    product = content.get('prod_id', None)
    quantity = content.get('quantity', None)

    if (not isinstance(product, int) and product > 0) or \
            (not isinstance(quantity, int) and quantity > 0):
        raise HTTPError(400, 'Invalid parameters for task')

    ret = None
    with utils.db_session() as session:
        query_res = session.query(models.Plan).get(plan_id)
        if not query_res:
            raise HTTPError(404, 'Plan not found')

        item = session.query(models.Inventory).get(product)
        if not item:
            raise HTTPError(400, 'Product does not exist')
        if item.quantity < quantity:
            raise HTTPError(400, 'Quantity of task exceeds central inventory')

        new_task = models.Task(plan_id, product, quantity)
        session.add(new_task)
        session.flush()

        link = url_for('get_tasks', task_id = new_task.id)
        ret = new_task.as_dict(link = link)

    return json.dumps(ret)
예제 #21
0
파일: views.py 프로젝트: derekzchu/planner
def update_tasks(task_id):
    """
    Updates a task. The follow operations are allowed by the client:
    1. Reparent the task's plan
    2. Change the product id iff the task has 0 workorders
    
    @param task_id pk
    @return success status
    """

    content = request.get_json()
    new_plan_id = content.get('plan_id', None)
    new_product_id = content.get('product_id', None)
    new_target_quantity = content.get('target_quantity', None)

    if new_target_quantity and (not isinstance(new_target_quantity, int)
                                or new_target_quantity <= 0):
        raise HTTPError(400, 'Invalid target quantity')

    with utils.db_session() as session:
        task = session.query(models.Task).get(task_id)
        if not task:
            raise HTTPError(404, 'Task not found')

        if new_plan_id:
            plan = session.query(models.Plan).get(new_plan_id)
            if not plan:
                raise HTTPError(404, 'Target plan not found')

            task.plan_id = new_plan_id
            session.flush()

        else:
            if new_product_id:
                #check if existing work orders
                if len(task.work_order) > 0:
                    raise HTTPError(
                        403,
                        'Task has existing work orders. Cannot alter product')

                task.product_id = new_product_id
                new_target_quantity = task.target_quantity

            if new_target_quantity:
                if not new_product_id:
                    new_product_id = task.product_id

                #check if there's enough inventory
                available_inventory = session.query(models.Inventory)\
                    .get(new_product_id)

                if not available_inventory or \
                        available_inventory.quantity < new_target_quantity :
                    raise HTTPError(403,
                                    'Task has Insufficient product quantity')

                task.target_quantity = new_target_quantity

            session.flush()

        link = url_for('get_tasks', tasks_id=task_id)
        ret = task.as_dict(link=link)
        return json.dumps(ret)
예제 #22
0
파일: views.py 프로젝트: derekzchu/planner
def update_work_order(work_id):
    """
    Updates the quantity for a work order.

    @return updated work order
    """
    ret = []
    content = request.get_json()
    quantity = content.get('actual_quantity', None)
    completed = content.get('completed', False)

    if quantity and quantity <= 0:
        raise HTTPError(400, 'Invalid parameters to update work order')

    with utils.db_session() as session:
        wo = session.query(models.WorkOrder).get(work_id)
        if not wo:
            raise HTTPError(404, 'Work order not found')

        query_res = session.query(\
            models.Inventory,
            models.WorkOrderInventory)\
            .outerjoin(models.WorkOrderInventory)\
            .filter(models.Inventory.id == wo.task.product_id)

        wo_inventory = None
        for result in query_res:
            central_inventory, wo_inventory = result

        if wo_inventory is None:
            wo_inventory = models.WorkOrderInventory(wo.task.product_id)
            session.add(wo_inventory)

        if quantity is not None:
            #check if work order quantity can be updated / started
            quantity_diff = quantity - wo.actual_quantity

            wo_inventory.active_inventory += quantity_diff
            if wo_inventory.active_inventory > central_inventory.quantity:
               raise HTTPError(403, 'Work order cannot be started because central inventory does not have enough product')

            wo.actual_quantity = quantity

        #Update the WO status. If it was NOTSTARTED before, mark as INPROGRESS
        if wo.status == Status.NOTSTARTED:
            wo.status = Status.INPROGRESS
            wo.task.status = Status.INPROGRESS
        if completed:
            if wo.actual_quantity <= 0:
                raise HTTPError(403, 'Cannot complete work order without any product applied')
            wo.status = Status.COMPLETED

        #Determine if all the WorkOrders are completed.
        total_wo = func.count(models.WorkOrder.id)
        total_completed = func.count(case(\
                [((models.WorkOrder.status == Status.COMPLETED), models.WorkOrder.id)], else_ = literal_column("NULL"))).label("total_wo_complete")
        sum_wo_quantity = func.sum(models.WorkOrder.actual_quantity)

        query_res = session.query(total_completed, total_wo, sum_wo_quantity).filter(models.WorkOrder.task_id == wo.task.id)
        for result in query_res:
            num_complete, num_wo, total_quantity = result

        if num_complete and num_wo and num_complete == num_wo:
            #All WorkOrders are complete. Update Central Inventory
#            wo.task.status = Status.COMPLETED
            wo_inventory.active_inventory -= total_quantity
            central_inventory.quantity -= total_quantity

        session.flush()
        link = url_for('get_work_order', work_id = work_id)
        ret.append(wo.as_dict(link = link))

    return json.dumps(ret)
예제 #23
0
파일: views.py 프로젝트: derekzchu/planner
def update_work_order(work_id):
    """
    Updates the quantity for a work order.

    @return updated work order
    """
    ret = []
    content = request.get_json()
    quantity = content.get('actual_quantity', None)
    completed = content.get('completed', False)

    if quantity and quantity <= 0:
        raise HTTPError(400, 'Invalid parameters to update work order')

    with utils.db_session() as session:
        wo = session.query(models.WorkOrder).get(work_id)
        if not wo:
            raise HTTPError(404, 'Work order not found')

        query_res = session.query(\
            models.Inventory,
            models.WorkOrderInventory)\
            .outerjoin(models.WorkOrderInventory)\
            .filter(models.Inventory.id == wo.task.product_id)

        wo_inventory = None
        for result in query_res:
            central_inventory, wo_inventory = result

        if wo_inventory is None:
            wo_inventory = models.WorkOrderInventory(wo.task.product_id)
            session.add(wo_inventory)

        if quantity is not None:
            #check if work order quantity can be updated / started
            quantity_diff = quantity - wo.actual_quantity

            wo_inventory.active_inventory += quantity_diff
            if wo_inventory.active_inventory > central_inventory.quantity:
                raise HTTPError(
                    403,
                    'Work order cannot be started because central inventory does not have enough product'
                )

            wo.actual_quantity = quantity

        #Update the WO status. If it was NOTSTARTED before, mark as INPROGRESS
        if wo.status == Status.NOTSTARTED:
            wo.status = Status.INPROGRESS
            wo.task.status = Status.INPROGRESS
        if completed:
            if wo.actual_quantity <= 0:
                raise HTTPError(
                    403,
                    'Cannot complete work order without any product applied')
            wo.status = Status.COMPLETED

        #Determine if all the WorkOrders are completed.
        total_wo = func.count(models.WorkOrder.id)
        total_completed = func.count(case(\
                [((models.WorkOrder.status == Status.COMPLETED), models.WorkOrder.id)], else_ = literal_column("NULL"))).label("total_wo_complete")
        sum_wo_quantity = func.sum(models.WorkOrder.actual_quantity)

        query_res = session.query(
            total_completed, total_wo,
            sum_wo_quantity).filter(models.WorkOrder.task_id == wo.task.id)
        for result in query_res:
            num_complete, num_wo, total_quantity = result

        if num_complete and num_wo and num_complete == num_wo:
            #All WorkOrders are complete. Update Central Inventory
            #            wo.task.status = Status.COMPLETED
            wo_inventory.active_inventory -= total_quantity
            central_inventory.quantity -= total_quantity

        session.flush()
        link = url_for('get_work_order', work_id=work_id)
        ret.append(wo.as_dict(link=link))

    return json.dumps(ret)