user_area.py 7.61 KB
import os
import colander
import logging
from deform import widget
from pyramid.view import view_config
from . import BaseView, btn_upload
from pyramid.path import AssetResolver
from . import BaseView, button_import, get_params
from ...models import DBSession, ResDesa, User, UserArea
from .desa import desa_widget, get_desa_list
from sqlalchemy import func
from pyramid.i18n import TranslationStringFactory
from opensipkd.tools.report import csv_response, file_response
from opensipkd.tools import get_random_string

_ = TranslationStringFactory('myapp')
log = logging.getLogger(__name__)

class ListSchema(colander.Schema):
    id = colander.SchemaNode(
        colander.Integer(),
        title="Action"
    )
    user_name = colander.SchemaNode(
        colander.String(),
        field=User.user_name,
        title="User"
    )
    desa_kd = colander.SchemaNode(
        colander.String(),
        field=ResDesa.kode)
    desa_name = colander.SchemaNode(
        colander.String(),
        field=ResDesa.nama)

@colander.deferred
def desa_checkbox_widget(node, kw):
    values = kw.get('desa_list', [])
    return widget.CheckboxChoiceWidget(values=values)

def single_choice_validator(node, value):
    """Validator untuk memastikan hanya satu opsi yang dipilih."""
    if len(value) > 1:
        raise colander.Invalid(node, "Hanya boleh memilih satu Kelurahan/Desa.")

class AddSchema(colander.Schema):
    user_id = colander.SchemaNode(
        colander.Integer(),
        widget=widget.SelectWidget(values=User.get_list()),
        oid="user_id",
        title="User",
    )
    desa_id = colander.SchemaNode(
        colander.Set(),
        widget=desa_checkbox_widget,
        validator=single_choice_validator,
        oid="desa_id",
        title="Kelurahan/Desa",
    )

class EditSchema(AddSchema):
    id = colander.SchemaNode(
        colander.String(),
        missing=colander.drop,
        widget=widget.HiddenWidget(readonly=True)
    )
    user_id = colander.SchemaNode(
        colander.Integer(),
        missing=colander.drop,
        widget=widget.SelectWidget(values=User.get_list(), readonly=True),  # Ditampilkan, tetapi readonly
        oid="user_id",
        title="User",
    )

class Views(BaseView):
    def __init__(self, request):
        super(Views, self).__init__(request)
        self.list_schema = ListSchema
        self.add_schema = AddSchema
        self.edit_schema = EditSchema
        self.list_route = 'user-area'
        self.table = UserArea
        self.list_buttons = self.list_buttons + self.list_report + (btn_upload,)
        path = os.path.dirname(__file__)
        path = os.path.dirname(path)
        self.report_file = os.path.join(path, 'reports', 'user_area.jrxml')

    def get_module_path(self, module_name):
        a = AssetResolver(module_name)
        resolver = a.resolve('')
        return resolver.abspath()

    def pdf_response(self, **kwargs):
        from opensipkd.base.tools.report import jasper_export
        logo = self.get_module_path('opensipkd.base')
        logo = os.path.join(logo, 'static', 'img', 'logo.png')
        parameters = {
            "judul": get_params('company', "openSIPKD"), 
            "alamat_lengkap": get_params('address', "Bekasi"),
            "logo": logo
        }
        filename = jasper_export(self.report_file, parameters=parameters)
        return file_response(self.req, filename=filename[0])
    
    @staticmethod
    def query_register():
        return DBSession.query(UserArea.user_id, UserArea.desa_id).order_by(UserArea.user_id)
    
    def csv_response(self, **kwargs):
        query = self.query_register()
        row = query.first()
        header = row._mapping.keys() if row else ['user_id', 'desa_id']
        rows = [list(item) for item in query.all()]
        filename = f"{get_random_string(16)}.csv"
        value = {
            'header': header,
            'rows': rows,
        }
        return csv_response(self.req, value, filename)

    def list_join(self, query, **kwargs):
        return query.outerjoin(ResDesa, ResDesa.id == self.table.desa_id) \
            .outerjoin(User, User.id == self.table.user_id)

    @view_config(route_name='user-area', renderer='templates/table.pt',
                 permission='user-view')
    def view_list(self, **kwargs):
        return super(Views, self).view_list(**kwargs)

    @view_config(route_name='user-area-act', renderer='json',
                 permission='user-view')
    def view_act(self):
        return super(Views, self).view_act()
    
    def get_bindings(self, row=None):
        return {
            "desa_list": get_desa_list()
        }

    @view_config(route_name='user-area-add', renderer='templates/form.pt',
                 permission='user-edit')
    def view_add(self):
        return super(Views, self).view_add()

    @view_config(route_name='user-area-view', renderer='templates/form.pt',
                 permission='user-view')
    def view_view(self):
        return super(Views, self).view_view()

    @view_config(route_name='user-area-delete', renderer='templates/form.pt',
                 permission='user-edit')
    def view_delete(self):
        return super(Views, self).view_delete()
    
    @view_config(route_name='user-area-upload',
                 renderer='templates/upload.pt', permission='user-upload')
    def view_upload(self):
        self.upload_keys = ["user_id"]
        return super(Views, self).view_upload(exts=('.csv', ".tsv"))

    @view_config(route_name='user-area-edit', renderer='templates/form.pt',
                 permission='user-edit')
    def view_edit(self):
        return super(Views, self).view_edit()
    
    def save_request(self, values, row=None):
        if row:  # Mode Edit: Perbarui entri yang ada
            desa_ids = values.get("desa_id")
            if desa_ids:
                desa_id = next(iter(desa_ids)) if desa_ids else None
                if desa_id is not None:
                    row.desa_id = int(desa_id)  # Perbarui desa_id pada row yang ada
                    # user_id tidak diubah, tetap dari row.user_id
                    DBSession.add(row)
                    DBSession.flush()
                    return row
            return None
        else:  # Mode Tambah: Buat entri baru tanpa menghapus entri lama
            user_id = values.get("user_id")
            if not user_id:
                return None  
            desa_ids = values.get("desa_id")
            if desa_ids:
                desa_id = next(iter(desa_ids)) if desa_ids else None
                if desa_id is not None:
                    new_row = UserArea(
                        user_id=user_id,
                        desa_id=int(desa_id)
                    )
                    DBSession.add(new_row)
                    DBSession.flush()
                    return new_row
            return None

    def get_existing_desa(self, user_id):
        q = DBSession.query(UserArea).filter_by(user_id=user_id)
        r = []
        for ug in q:
            r.append(str(ug.desa_id))
        return set(r)
    
    def get_values(self, row, istime=False):
        # Call the parent class's get_values to get the base dictionary
        d = super(Views, self).get_values(row, istime)
        
        # Populate the form with the existing data from the selected row
        d["id"] = str(row.id)  # Hidden field for the row ID
        d["user_id"] = row.user_id  # Pre-fill user_id (readonly in edit form)
        d["desa_id"] = {str(row.desa_id)}  # Pre-fill desa_id as a single-item set
        
        return d