Exemple #1
0
    def test_deserialize_empty(self):
        from c2cgeoform.ext.deform_ext import RelationSelect2Widget
        widget = RelationSelect2Widget(Tag, 'id', 'name', multiple=True)
        renderer = DummyRenderer()

        field = _get_field('tags', renderer)
        widget.populate(DBSession, None)
        result = widget.deserialize(field, null)
        self.assertEqual(result, [])
Exemple #2
0
    def test_serialize_empty(self):
        from c2cgeoform.ext.deform_ext import RelationSelect2Widget
        widget = RelationSelect2Widget(Tag, 'id', 'name', multiple=True)
        renderer = DummyRenderer()

        field = _get_field('tags', renderer)
        widget.populate(DBSession, None)
        widget.serialize(field, null)
        self.assertEqual(renderer.kw['values'], _convert_values(widget.values))
        self.assertEqual(renderer.kw['cstruct'], [])

        first_value = renderer.kw['values'][0]
        self.assertEqual('0', first_value[0])
        self.assertEqual('Tag A', first_value[1])
Exemple #3
0
    def test_serialize_wrong_mapping(self):
        from c2cgeoform.ext.deform_ext import RelationSelect2Widget
        widget = RelationSelect2Widget(EmploymentStatus,
                                       'id',
                                       'name',
                                       multiple=True)
        renderer = DummyRenderer()

        field = _get_field('tags', renderer)
        widget.populate(DBSession, None)
        objs = [{'bad_column': '101'}, {'bad_column': '102'}]

        with self.assertRaises(KeyError):
            widget.serialize(field, objs)
Exemple #4
0
    def test_serialize_wrong_mapping(self):
        from c2cgeoform.ext.deform_ext import RelationSelect2Widget
        widget = RelationSelect2Widget(
            EmploymentStatus, 'id', 'name', multiple=True)
        renderer = DummyRenderer()

        field = _get_field('tags', renderer)
        widget.populate(DBSession, None)
        objs = [
            {'tag_id': '0', 'personId': '1', 'id': '101'},
            {'tag_id': '2', 'personId': '1', 'id': '102'}]

        self.assertRaises(
            RuntimeError,
            widget.serialize,
            field,
            objs)
Exemple #5
0
    def test_serialize(self):
        from c2cgeoform.ext.deform_ext import RelationSelect2Widget
        widget = RelationSelect2Widget(Tag, 'id', 'name', multiple=True)
        renderer = DummyRenderer()

        field = _get_field('tags', renderer)
        widget.populate(DBSession, None)
        objs = [
            {'tag_id': '0', 'personId': '1', 'id': '101'},
            {'tag_id': '2', 'personId': '1', 'id': '102'}]

        widget.serialize(field, objs)
        self.assertEqual(renderer.kw['values'], _convert_values(widget.values))
        self.assertEqual(renderer.kw['cstruct'], ['0', '2'])

        first_value = renderer.kw['values'][0]
        self.assertEqual('0', first_value[0])
        self.assertEqual('Tag A', first_value[1])
Exemple #6
0
    def test_serialize_default_value(self):
        from c2cgeoform.ext.deform_ext import RelationSelect2Widget
        widget = RelationSelect2Widget(
            EmploymentStatus, 'id', 'name', ('', '- Select -'))

        renderer = DummyRenderer()
        field = DummyField(None, renderer=renderer)
        widget.populate(DBSession, None)
        widget.serialize(field, null)
        self.assertEqual(renderer.kw['values'], _convert_values(widget.values))

        # first the default value
        first_value = renderer.kw['values'][0]
        self.assertEqual('', first_value[0])
        self.assertEqual('- Select -', first_value[1])

        # then the values loaded from the db
        snd_value = renderer.kw['values'][1]
        self.assertEqual('0', snd_value[0])
        self.assertEqual('Worker', snd_value[1])
Exemple #7
0
class Demande(Base):
    __tablename__ = 'demande'
    __table_args__ = ({"schema": schema})

    __colanderalchemy_config__ = {
        'title': _('Demande d\'abattage d\'arbres'),
        'plural': _('Demande d\'abattage d\'arbres')
    }

    id = Column(Integer,
                primary_key=True,
                info={'colanderalchemy': {
                    'widget': HiddenWidget()
                }})
    hash = Column(Text,
                  unique=True,
                  default=lambda: str(uuid4()),
                  info={
                      'colanderalchemy': {
                          'widget': HiddenWidget()
                      },
                      'c2cgeoform': {
                          'duplicate': False
                      }
                  })
    proprietaire = Column(Text, nullable=False)
    adresse = Column(Text, nullable=False)
    type_travaux_id = Column(Integer,
                             ForeignKey('{}.type_travaux.id'.format(schema)),
                             nullable=False,
                             info={
                                 'colanderalchemy': {
                                     'title':
                                     _('Type de travaux'),
                                     'description':
                                     _('Type de travaux à entreprendre'),
                                     'widget':
                                     deform_ext.RelationRadioChoiceWidget(
                                         Type_travaux,
                                         'id',
                                         'name',
                                         order_by='id',
                                         inline=True)
                                 }
                             })
    type_arborisation_id = Column(
        Integer,
        ForeignKey('{}.type_arborisation.id'.format(schema)),
        nullable=False,
        info={
            'colanderalchemy': {
                'title':
                _('Type d\'arborisation'),
                'widget':
                RelationSelect2Widget(Type_arborisation,
                                      'id',
                                      'name',
                                      order_by='id',
                                      default_value=('', _('- Select -')))
            }
        })
    essence = Column(Text, nullable=False)
    diametre = Column(Numeric(5, 2), nullable=False)
    hauteur = Column(Numeric(5, 2), nullable=False)
    motif = Column(Text,
                   nullable=False,
                   info={
                       'colanderalchemy': {
                           'title': _('Motif'),
                           'widget': deform.widget.TextAreaWidget(rows=3),
                       }
                   })
    email = Column(Text,
                   nullable=False,
                   info={
                       'colanderalchemy': {
                           'title': _('E-mail'),
                           'validator': colander.Email()
                       }
                   })
    date_demande = Column(Date,
                          info={'colanderalchemy': {
                              'widget': HiddenWidget()
                          }},
                          default=lambda: date.today())

    location_position = Column(geoalchemy2.Geometry('POINT',
                                                    4326,
                                                    management=True),
                               info={
                                   'colanderalchemy': {
                                       'title':
                                       _('Position'),
                                       'typ':
                                       colander_ext.Geometry('POINT',
                                                             srid=4326,
                                                             map_srid=3857),
                                       'widget':
                                       deform_ext.MapWidget(
                                           center=[741934, 5863213],
                                           zoom=14,
                                           fit_max_zoom=18)
                                   }
                               },
                               nullable=False)

    type_travaux = relationship('Type_travaux',
                                info={'colanderalchemy': {
                                    'exclude': True
                                }})
    type_arborisation = relationship(
        'Type_arborisation', info={'colanderalchemy': {
            'exclude': True
        }})
Exemple #8
0
class Person(Base):
    __tablename__ = 'tests_persons'
    __colanderalchemy_config__ = {
        'title': 'A Person',
        'description': 'Tell us about you.'
    }

    id = Column(Integer,
                primary_key=True,
                info={
                    'colanderalchemy': {
                        'title': 'ID',
                        'widget': deform.widget.HiddenWidget(),
                        'admin_list': True
                    }
                })
    hash = Column(Text, unique=True)
    name = Column(
        Text,
        nullable=False,
        info={'colanderalchemy': {
            'title': 'Your name',
            'admin_list': True
        }})
    first_name = Column(Text,
                        nullable=False,
                        info={'colanderalchemy': {
                            'title': 'Your first name'
                        }})
    age = Column(Integer,
                 info={
                     'colanderalchemy': {
                         'title': 'Your age',
                         'validator': colander.Range(18, )
                     }
                 })
    phones = relationship(
        Phone,
        cascade="all, delete-orphan",
        info={'colanderalchemy': {
            'title': 'Phone numbers',
        }})
    tags = relationship(TagsForPerson,
                        cascade="all, delete-orphan",
                        info={
                            'colanderalchemy': {
                                'title':
                                'Tags',
                                'widget':
                                RelationSelect2Widget(Tag,
                                                      'id',
                                                      'name',
                                                      order_by='name',
                                                      multiple=True)
                            }
                        })
    validated = Column(Boolean,
                       info={
                           'colanderalchemy': {
                               'title': 'Validation',
                               'label': 'Validated'
                           }
                       })
Exemple #9
0
class User(Base):
    __tablename__ = "user"
    __table_args__ = {"schema": _schema}
    __colanderalchemy_config__ = {"title": _("User"), "plural": _("Users")}
    __c2cgeoform_config__ = {"duplicate": True}
    item_type = Column("type",
                       String(10),
                       nullable=False,
                       info={"colanderalchemy": {
                           "widget": HiddenWidget()
                       }})
    __mapper_args__ = {
        "polymorphic_on": item_type,
        "polymorphic_identity": "user"
    }

    id = Column(Integer,
                primary_key=True,
                info={"colanderalchemy": {
                    "widget": HiddenWidget()
                }})
    username = Column(Unicode,
                      unique=True,
                      nullable=False,
                      info={"colanderalchemy": {
                          "title": _("Username")
                      }})
    _password = Column("password",
                       Unicode,
                       nullable=False,
                       info={"colanderalchemy": {
                           "exclude": True
                       }})
    temp_password = Column("temp_password",
                           Unicode,
                           nullable=True,
                           info={"colanderalchemy": {
                               "exclude": True
                           }})
    tech_data = Column(MutableDict.as_mutable(HSTORE),
                       info={"colanderalchemy": {
                           "exclude": True
                       }})
    email = Column(
        Unicode,
        nullable=False,
        info={"colanderalchemy": {
            "title": _("Email"),
            "validator": Email()
        }})
    is_password_changed = Column(Boolean,
                                 default=False,
                                 info={
                                     "colanderalchemy": {
                                         "title":
                                         _("The user changed his password")
                                     }
                                 })

    settings_role_id = Column(
        Integer,
        info={
            "colanderalchemy": {
                "title":
                _("Settings from role"),
                "description":
                "Only used for settings not for permissions",
                "widget":
                RelationSelect2Widget(Role,
                                      "id",
                                      "name",
                                      order_by="name",
                                      default_value=("", _("- Select -"))),
            }
        },
    )

    settings_role = relationship(
        Role,
        foreign_keys="User.settings_role_id",
        primaryjoin="Role.id==User.settings_role_id",
        info={
            "colanderalchemy": {
                "title": _("Settings role"),
                "exclude": True
            }
        },
    )

    roles = relationship(
        Role,
        secondary=user_role,
        secondaryjoin=Role.id == user_role.c.role_id,
        backref=backref("users",
                        order_by="User.username",
                        info={"colanderalchemy": {
                            "exclude": True
                        }}),
        info={"colanderalchemy": {
            "title": _("Roles"),
            "exclude": True
        }},
    )

    last_login = Column(
        DateTime(timezone=True),
        info={
            "colanderalchemy": {
                "title": _("Last login"),
                "missing": drop,
                "widget": DateTimeInputWidget(readonly=True),
            }
        },
    )

    expire_on = Column(
        DateTime(timezone=True),
        info={"colanderalchemy": {
            "title": _("Expiration date")
        }})

    deactivated = Column(Boolean,
                         default=False,
                         info={"colanderalchemy": {
                             "title": _("Deactivated")
                         }})

    def __init__(
        self,
        username: str = "",
        password: str = "",
        email: str = "",
        is_password_changed: bool = False,
        settings_role: Role = None,
        roles: List[Role] = None,
        expire_on: datetime = None,
        deactivated: bool = False,
    ) -> None:
        self.username = username
        self.password = password
        self.tech_data = {}
        self.email = email
        self.is_password_changed = is_password_changed
        if settings_role:
            self.settings_role = settings_role
        self.roles = roles or []
        self.expire_on = expire_on
        self.deactivated = deactivated

    @property
    def password(self) -> str:
        """returns password"""
        return self._password  # type: ignore

    @password.setter
    def password(self, password: str) -> None:
        """encrypts password on the fly."""
        self._password = self.__encrypt_password(password)

    def set_temp_password(self, password: str) -> None:
        """encrypts password on the fly."""
        self.temp_password = self.__encrypt_password(password)

    @staticmethod
    def __encrypt_password_legacy(password: str) -> str:
        """Hash the given password with SHA1."""
        return sha1(password.encode("utf8")).hexdigest()  # nosec

    @staticmethod
    def __encrypt_password(password: str) -> str:
        return crypt.crypt(password, crypt.METHOD_SHA512)

    def validate_password(self, passwd: str) -> bool:
        """Check the password against existing credentials.
        this method _MUST_ return a boolean.

        @param passwd: the password that was provided by the user to
        try and authenticate. This is the clear text version that we will
        need to match against the (possibly) encrypted one in the database.
        """
        if self._password.startswith("$"):
            # new encryption method
            if compare_hash(self._password,
                            crypt.crypt(passwd, self._password)):
                return True
        else:
            # legacy encryption method
            if compare_hash(self._password,
                            self.__encrypt_password_legacy(passwd)):
                # convert to the new encryption method
                self._password = self.__encrypt_password(passwd)
                return True

        if (self.temp_password is not None and self.temp_password != ""
                and compare_hash(self.temp_password,
                                 crypt.crypt(passwd, self.temp_password))):
            self._password = self.temp_password
            self.temp_password = None
            self.is_password_changed = False
            return True
        return False

    def expired(self) -> bool:
        return self.expire_on is not None and self.expire_on < datetime.now(
            pytz.utc)

    def update_last_login(self) -> None:
        self.last_login = datetime.now(pytz.utc)

    def __str__(self) -> str:
        return self.username or ""
Exemple #10
0
class LayerWMS(DimensionLayer):
    __tablename__ = "layer_wms"
    __table_args__ = {"schema": _schema}
    __colanderalchemy_config__ = {
        "title": _("WMS Layer"),
        "plural": _("WMS Layers")
    }

    __c2cgeoform_config__ = {"duplicate": True}

    __mapper_args__ = {"polymorphic_identity": "l_wms"}

    id = Column(
        Integer,
        ForeignKey(_schema + ".layer.id", ondelete="CASCADE"),
        primary_key=True,
        info={"colanderalchemy": {
            "missing": None,
            "widget": HiddenWidget()
        }},
    )
    ogc_server_id = Column(
        Integer,
        ForeignKey(_schema + ".ogc_server.id"),
        nullable=False,
        info={
            "colanderalchemy": {
                "title":
                _("OGC server"),
                "column":
                2,
                "widget":
                RelationSelect2Widget(OGCServer,
                                      "id",
                                      "name",
                                      order_by="name",
                                      default_value=("", _("- Select -"))),
            }
        },
    )
    layer = Column(
        Unicode,
        nullable=False,
        info={"colanderalchemy": {
            "title": _("WMS layer name"),
            "column": 2
        }})
    style = Column(
        Unicode, info={"colanderalchemy": {
            "title": _("Style"),
            "column": 2
        }})
    valid = Column(
        Boolean,
        info={
            "colanderalchemy": {
                "title": _("Valid"),
                "column": 2,
                "widget": CheckboxWidget(readonly=True)
            }
        },
    )
    invalid_reason = Column(
        Unicode,
        info={
            "colanderalchemy": {
                "title": _("Reason why I am not valid"),
                "column": 2,
                "widget": TextInputWidget(readonly=True),
            }
        },
    )
    time_mode = Column(
        Enum("disabled", "value", "range", native_enum=False),
        default="disabled",
        nullable=False,
        info={
            "colanderalchemy": {
                "title":
                _("Time mode"),
                "column":
                2,
                "widget":
                SelectWidget(values=(("disabled", _("Disabled")), ("value",
                                                                   _("Value")),
                                     ("range", _("Range")))),
            }
        },
    )
    time_widget = Column(
        Enum("slider", "datepicker", native_enum=False),
        default="slider",
        nullable=False,
        info={
            "colanderalchemy": {
                "title":
                _("Time widget"),
                "column":
                2,
                "widget":
                SelectWidget(values=(("slider", _("Slider")),
                                     ("datepicker", _("Datepicker")))),
            }
        },
    )

    # relationship with OGCServer
    ogc_server = relationship(
        "OGCServer",
        info={"colanderalchemy": {
            "title": _("OGC server"),
            "exclude": True
        }})

    def __init__(
        self,
        name: str = "",
        layer: str = "",
        public: bool = True,
        time_mode: str = "disabled",
        time_widget: str = "slider",
    ) -> None:
        DimensionLayer.__init__(self, name=name, public=public)
        self.layer = layer
        self.time_mode = time_mode
        self.time_widget = time_widget

    @staticmethod
    def get_default(dbsession: Session) -> Optional[DimensionLayer]:
        return cast(
            Optional[DimensionLayer],
            dbsession.query(LayerWMS).filter(
                LayerWMS.name == "wms-defaults").one_or_none(),
        )
Exemple #11
0
class User(Base):
    __tablename__ = 'user'
    __table_args__ = {'schema': _schema}
    __colanderalchemy_config__ = {'title': _('User'), 'plural': _('Users')}
    __c2cgeoform_config__ = {'duplicate': True}
    item_type = Column('type',
                       String(10),
                       nullable=False,
                       info={'colanderalchemy': {
                           'widget': HiddenWidget()
                       }})
    __mapper_args__ = {
        'polymorphic_on': item_type,
        'polymorphic_identity': 'user',
    }

    id = Column(Integer,
                primary_key=True,
                info={'colanderalchemy': {
                    'widget': HiddenWidget()
                }})
    username = Column(Unicode,
                      unique=True,
                      nullable=False,
                      info={'colanderalchemy': {
                          'title': _('Username')
                      }})
    _password = Column('password',
                       Unicode,
                       nullable=False,
                       info={'colanderalchemy': {
                           'exclude': True
                       }})
    temp_password = Column('temp_password',
                           Unicode,
                           nullable=True,
                           info={'colanderalchemy': {
                               'exclude': True
                           }})
    tech_data = Column(MutableDict.as_mutable(HSTORE),
                       info={'colanderalchemy': {
                           'exclude': True
                       }})
    email = Column(
        Unicode,
        nullable=False,
        info={'colanderalchemy': {
            'title': _('Email'),
            'validator': Email()
        }})
    is_password_changed = Column(Boolean,
                                 default=False,
                                 info={
                                     'colanderalchemy': {
                                         'title':
                                         _('The user changed his password')
                                     }
                                 })

    settings_role_id = Column(
        Integer,
        info={
            'colanderalchemy': {
                'title':
                _('Settings from role'),
                'description':
                'Only used for settings not for permissions',
                'widget':
                RelationSelect2Widget(Role,
                                      'id',
                                      'name',
                                      order_by='name',
                                      default_value=('', _('- Select -')))
            }
        })

    settings_role = relationship(Role,
                                 foreign_keys='User.settings_role_id',
                                 primaryjoin='Role.id==User.settings_role_id',
                                 info={
                                     'colanderalchemy': {
                                         'title': _('Settings role'),
                                         'exclude': True
                                     }
                                 })

    roles = relationship(
        Role,
        secondary=user_role,
        secondaryjoin=Role.id == user_role.c.role_id,
        backref=backref('users', info={'colanderalchemy': {
            'exclude': True
        }}),
        info={'colanderalchemy': {
            'title': _('Roles'),
            'exclude': True
        }})

    last_login = Column(DateTime(timezone=True),
                        info={
                            'colanderalchemy': {
                                'title': _('Last login'),
                                'missing': drop,
                                'widget': DateTimeInputWidget(readonly=True)
                            }
                        })

    expire_on = Column(
        DateTime(timezone=True),
        info={'colanderalchemy': {
            'title': _('Expiration date')
        }})

    deactivated = Column(Boolean,
                         default=False,
                         info={'colanderalchemy': {
                             'title': _('Deactivated')
                         }})

    def __init__(self,
                 username: str = '',
                 password: str = '',
                 email: str = '',
                 is_password_changed: bool = False,
                 settings_role: Role = None,
                 roles: List[Role] = [],
                 expire_on: datetime = None,
                 deactivated: bool = False) -> None:
        self.username = username
        self.password = password
        self.tech_data = {}
        self.email = email
        self.is_password_changed = is_password_changed
        if settings_role:
            self.settings_role = settings_role
        self.roles = roles
        self.expire_on = expire_on
        self.deactivated = deactivated

    @property
    def password(self) -> str:
        """returns password"""
        return self._password  # pragma: no cover

    @password.setter
    def password(self, password: str) -> None:
        """encrypts password on the fly."""
        self._password = self.__encrypt_password(password)

    def set_temp_password(self, password: str) -> None:
        """encrypts password on the fly."""
        self.temp_password = self.__encrypt_password(password)

    @staticmethod
    def __encrypt_password_legacy(password: str) -> str:
        """Hash the given password with SHA1."""
        return sha1(password.encode('utf8')).hexdigest()  # nosec

    @staticmethod
    def __encrypt_password(password: str) -> str:
        # TODO: remove pylint disable when https://github.com/PyCQA/pylint/issues/3047 is fixed
        return crypt.crypt(password, crypt.METHOD_SHA512)  # pylint: disable=E1101

    def validate_password(self, passwd: str) -> bool:
        """Check the password against existing credentials.
        this method _MUST_ return a boolean.

        @param passwd: the password that was provided by the user to
        try and authenticate. This is the clear text version that we will
        need to match against the (possibly) encrypted one in the database.
        """
        if self._password.startswith('$'):
            # new encryption method
            if compare_hash(self._password,
                            crypt.crypt(passwd, self._password)):
                return True
        else:
            # legacy encryption method
            if compare_hash(self._password,
                            self.__encrypt_password_legacy(passwd)):
                # convert to the new encryption method
                self._password = self.__encrypt_password(passwd)
                return True

        if \
                self.temp_password is not None and \
                self.temp_password != '' and \
                compare_hash(self.temp_password, crypt.crypt(passwd, self.temp_password)):
            self._password = self.temp_password
            self.temp_password = None
            self.is_password_changed = False
            return True
        return False

    def expired(self) -> bool:
        return self.expire_on is not None and self.expire_on < datetime.now(
            pytz.utc)

    def update_last_login(self) -> None:
        self.last_login = datetime.now(pytz.utc)

    def __unicode__(self) -> str:
        return self.username or ''  # pragma: no cover
Exemple #12
0
class Person(Base):
    __tablename__ = 'tests_persons'
    __colanderalchemy_config__ = {
        'title': 'A Person',
        'description': 'Tell us about you.'
    }
    __c2cgeoform_config__ = {'duplicate': True}

    id = Column(Integer,
                primary_key=True,
                info={
                    'colanderalchemy': {
                        'title': 'ID',
                        'widget': deform.widget.HiddenWidget()
                    }
                })
    hash = Column(Text, unique=True)
    name = Column(Text,
                  nullable=False,
                  info={
                      'colanderalchemy': {
                          'title': 'Your name',
                      },
                      'c2cgeoform': {
                          'duplicate': True
                      }
                  })
    first_name = Column(Text,
                        nullable=False,
                        info={
                            'colanderalchemy': {
                                'title': 'Your first name'
                            },
                            'c2cgeoform': {
                                'duplicate': True
                            }
                        })
    age = Column(Integer,
                 info={
                     'colanderalchemy': {
                         'title': 'Your age',
                         'validator': colander.Range(18, )
                     }
                 })
    phones = relationship(
        Phone,
        cascade="all, delete-orphan",
        info={'colanderalchemy': {
            'title': 'Phone numbers',
        }})
    tags = relationship("Tag",
                        secondary=person_tag,
                        cascade="save-update,merge,refresh-expire",
                        info={
                            'colanderalchemy': {
                                'title':
                                'Tags',
                                'widget':
                                RelationSelect2Widget(Tag,
                                                      'id',
                                                      'name',
                                                      order_by='name',
                                                      multiple=True),
                                'includes': ['id']
                            }
                        })

    validated = Column(Boolean,
                       info={
                           'colanderalchemy': {
                               'title': 'Validation',
                               'label': 'Validated'
                           }
                       })
Exemple #13
0
class LayerWMS(DimensionLayer):
    __tablename__ = 'layer_wms'
    __table_args__ = {'schema': _schema}
    __colanderalchemy_config__ = {
        'title': _('WMS Layer'),
        'plural': _('WMS Layers')
    }

    __c2cgeoform_config__ = {'duplicate': True}

    __mapper_args__ = {'polymorphic_identity': 'l_wms'}

    id = Column(
        Integer,
        ForeignKey(_schema + '.layer.id', ondelete='CASCADE'),
        primary_key=True,
        info={'colanderalchemy': {
            'missing': None,
            'widget': HiddenWidget()
        }})
    ogc_server_id = Column(Integer,
                           ForeignKey(_schema + '.ogc_server.id'),
                           nullable=False,
                           info={
                               'colanderalchemy': {
                                   'title':
                                   _('OGC server'),
                                   'column':
                                   2,
                                   'widget':
                                   RelationSelect2Widget(
                                       OGCServer,
                                       'id',
                                       'name',
                                       order_by='name',
                                       default_value=('', _('- Select -')))
                               }
                           })
    layer = Column(
        Unicode,
        nullable=False,
        info={'colanderalchemy': {
            'title': _('WMS layer name'),
            'column': 2
        }})
    style = Column(
        Unicode, info={'colanderalchemy': {
            'title': _('Style'),
            'column': 2
        }})
    time_mode = Column(Enum('disabled', 'value', 'range', native_enum=False),
                       default='disabled',
                       nullable=False,
                       info={
                           'colanderalchemy': {
                               'title':
                               _('Time mode'),
                               'column':
                               2,
                               'widget':
                               SelectWidget(values=(('disabled',
                                                     _('Disabled')),
                                                    ('value', _('Value')),
                                                    ('range', _('Range'))))
                           }
                       })
    time_widget = Column(Enum('slider', 'datepicker', native_enum=False),
                         default='slider',
                         nullable=False,
                         info={
                             'colanderalchemy': {
                                 'title':
                                 _('Time widget'),
                                 'column':
                                 2,
                                 'widget':
                                 SelectWidget(values=(('slider', _('Slider')),
                                                      ('datepicker',
                                                       _('Datepicker'))))
                             }
                         })

    # relationship with OGCServer
    ogc_server = relationship(
        'OGCServer',
        info={'colanderalchemy': {
            'title': _('OGC server'),
            'exclude': True
        }})

    def __init__(self,
                 name: str = '',
                 layer: str = '',
                 public: bool = True,
                 time_mode: str = 'disabled',
                 time_widget: str = 'slider') -> None:
        DimensionLayer.__init__(self, name=name, public=public)
        self.layer = layer
        self.time_mode = time_mode
        self.time_widget = time_widget

    @staticmethod
    def get_default(dbsession: Session) -> DimensionLayer:
        return dbsession.query(LayerWMS).filter(
            LayerWMS.name == 'wms-defaults').one_or_none()
class Excavation(Base):
    __tablename__ = 'excavation'
    __table_args__ = (
        {"schema": schema}
    )
    __colanderalchemy_config__ = {
        'title':
        _('Application form for permission to carry out excavation work'),
        'plural': _('Excavation forms')
    }

    __c2cgeoform_config__ = {
        'duplicate': True
    }

    id = Column(Integer, primary_key=True, info={
        # the `colanderalchemy` property allows to set a custom title for the
        # column or to use a specific widget.
        'colanderalchemy': {
            'title': _('Permission Number'),
            'widget': HiddenWidget()
        }})
    hash = Column(Text, unique=True, default=lambda: str(uuid4()), info={
        'colanderalchemy': {
            'widget': HiddenWidget()
        },
        'c2cgeoform': {
            'duplicate': False
        }})
    reference_number = Column(Text, nullable=True, info={
        'colanderalchemy': {
            'title': _('Reference Number')
        },
        'c2cgeoform': {
            'duplicate': False
        }})
    request_date = Column(Date, nullable=True, info={
        'colanderalchemy': {
            'title': _('Request Date')
        }})

    description = Column(Text, nullable=True, info={
        'colanderalchemy': {
            'title': _('Description of the Work'),
            'widget': deform.widget.TextAreaWidget(rows=3),
        }})
    motif = Column(Text, nullable=True, info={
        'colanderalchemy': {
            'title': _('Motive for the Work'),
            'widget': deform.widget.TextAreaWidget(rows=3),
        }})

    situations = relationship(
        "Situation",
        secondary=situation_for_permission,
        order_by=Situation.name,
        cascade="save-update,merge,refresh-expire",
        info={'colanderalchemy': {'exclude': True}})

    # by default a Deform sequence widget is used for relationship columns,
    # which, for example, allows to create new contact persons in a sub-form.
    contact_persons = relationship(
        ContactPerson,
        # make sure persons are deleted when removed from the relation
        cascade="all, delete-orphan",
        info={'colanderalchemy': {
                'title': _('Contact Persons')
        }})
    location_district_id = Column(
        Integer,
        ForeignKey('c2cgeoform_demo.district.id'),
        info={
            'colanderalchemy': {
                'title': _('District'),
                'widget': RelationSelect2Widget(
                    District,
                    'id',
                    'name',
                    order_by='name',
                    default_value=('', _('- Select -'))
                )
            }
        }
    )
    # if the name for the options should be internationalized, one
    # can create columns like 'name_fr' and 'name_de' in the table
    # 'District'. then in the translation files, the column name
    # can be "translated" (e.g. the French "translation" for the
    # column name would be 'name_fr'). to apply the translation use
    # the label `_('name'))` instead of `name`.

    location_street = Column(Text, nullable=False, info={
        'colanderalchemy': {
            'title': _('Street')
        }})
    location_postal_code = Column(Text, nullable=False, info={
        'colanderalchemy': {
            'title': _('Postal Code')
        }})
    location_town = Column(Text, nullable=False, info={
        'colanderalchemy': {
            'title': _('Town')
        }})
    # this is a search field to search for an address
    address_id = Column(
        Integer,
        ForeignKey('c2cgeoform_demo.address.id'),
        info={
            'colanderalchemy': {
                'title': _('Address'),
                'widget': RelationSearchWidget(
                    url=lambda request: request.route_url('addresses'),
                    model=Address,
                    min_length=1,
                    id_field='id',
                    label_field='label'
                )
            }
        }
    )
    # to show a map for a geometry column, the column has to be defined as
    # follows.
    location_position = Column(
        geoalchemy2.Geometry('POINT', 4326, management=True), info={
            'colanderalchemy': {
                'title': _('Position'),
                'typ':
                colander_ext.Geometry('POINT', srid=4326, map_srid=3857),
                'widget': deform_ext.MapWidget()
            }})

    # Person in Charge for the Work
    responsible_title = Column(Text, nullable=True, info={
        'colanderalchemy': {
            'title': _('Title'),
            'validator': colander.OneOf(['mr', 'mrs']),
            'widget': deform.widget.SelectWidget(values=(
                ('', _('- Select -')),
                ('mr', _('Mr.')),
                ('mrs', _('Mrs.'))
            ))
        }})
    responsible_name = Column(Text, nullable=True, info={
        'colanderalchemy': {
            'title': _('Name')
        }})
    responsible_first_name = Column(Text, nullable=True, info={
        'colanderalchemy': {
            'title': _('First Name')
        }})
    responsible_mobile = Column(Text, nullable=True, info={
        'colanderalchemy': {
            'title': _('Mobile Phone')
        }})
    responsible_mail = Column(Text, nullable=True, info={
        'colanderalchemy': {
            'title': _('Mail'),
            'validator': colander.Email()
        }})
    responsible_company = Column(Text, nullable=True, info={
        'colanderalchemy': {
            'title': _('Company')
        }})

    validated = Column(Boolean, info={
        'colanderalchemy': {
            'title': _('Validation'),
            'label': _('Validated')
        },
        'c2cgeoform': {
            'duplicate': False
        }})

    # Work footprint
    work_footprint = Column(
        geoalchemy2.Geometry('MULTIPOLYGON', 4326, management=True), info={
            'colanderalchemy': {
                'title': _('Footprint for the Work'),
                'typ': colander_ext.Geometry(
                    'MULTIPOLYGON', srid=4326, map_srid=3857),
                'widget': deform_ext.MapWidget()
            }})

    # Photo
    photos = relationship(
        Photo,
        cascade="all, delete-orphan",
        info={
            'colanderalchemy': {
                'title': _('Photo')
            }})
Exemple #15
0
class User(Base):  # type: ignore
    """The user table representation."""

    __tablename__ = "user"
    __table_args__ = {"schema": _schema}
    __colanderalchemy_config__ = {
        "title":
        _("User"),
        "plural":
        _("Users"),
        "description":
        Literal(
            _("""
            <div class="help-block">
                <p>Each user may have from 1 to n roles, but each user has a default role from
                    which are taken some settings. The default role (defined through the
                    "Settings from role" selection) has an influence on the role extent and on some
                    functionalities regarding their configuration.</p>

                <p>Role extents for users can only be set in one role, because the application
                    is currently not able to check multiple extents for one user, thus it is the
                    default role which defines this unique extent.</p>

                <p>Any functionality specified as <b>single</b> can be defined only once per user.
                    Hence, these functionalities have to be defined in the default role.</p>

                <p>By default, functionalities are not specified as <b>single</b>. Currently, the
                    following functionalities are of <b>single</b> type:</p>

                <ul>
                    <li><code>default_basemap</code></li>
                    <li><code>default_theme</code></li>
                    <li><code>preset_layer_filter</code></li>
                    <li><code>open_panel</code></li>
                </ul>

                <p>Any other functionality (with <b>single</b> not set or set to <code>false</code>) can
                    be defined in any role linked to the user.</p>
                <hr>
            </div>
                """)),
    }
    __c2cgeoform_config__ = {"duplicate": True}
    item_type = Column("type",
                       String(10),
                       nullable=False,
                       info={"colanderalchemy": {
                           "widget": HiddenWidget()
                       }})
    __mapper_args__ = {
        "polymorphic_on": item_type,
        "polymorphic_identity": "user"
    }

    id = Column(Integer,
                primary_key=True,
                info={"colanderalchemy": {
                    "widget": HiddenWidget()
                }})
    username = Column(
        Unicode,
        unique=True,
        nullable=False,
        info={
            "colanderalchemy": {
                "title": _("Username"),
                "description":
                _("Name used for authentication (must be unique)."),
            }
        },
    )
    _password = Column("password",
                       Unicode,
                       nullable=False,
                       info={"colanderalchemy": {
                           "exclude": True
                       }})
    temp_password = Column("temp_password",
                           Unicode,
                           nullable=True,
                           info={"colanderalchemy": {
                               "exclude": True
                           }})
    tech_data = Column(MutableDict.as_mutable(HSTORE),
                       info={"colanderalchemy": {
                           "exclude": True
                       }})
    email = Column(
        Unicode,
        nullable=False,
        info={
            "colanderalchemy": {
                "title":
                _("Email"),
                "description":
                _("Used to send emails to the user, for example in case of password recovery."
                  ),
                "validator":
                Email(),
            }
        },
    )
    is_password_changed = Column(
        Boolean,
        default=False,
        info={
            "colanderalchemy": {
                "title": _("The user changed his password"),
                "description":
                _("Indicates if user has changed his password."),
            }
        },
    )

    settings_role_id = Column(
        Integer,
        info={
            "colanderalchemy": {
                "title":
                _("Settings from role"),
                "description":
                _("Used to get some settings for the user (not for permissions)."
                  ),
                "widget":
                RelationSelect2Widget(Role,
                                      "id",
                                      "name",
                                      order_by="name",
                                      default_value=("", _("- Select -"))),
            }
        },
    )

    settings_role = relationship(
        Role,
        foreign_keys="User.settings_role_id",
        primaryjoin="Role.id==User.settings_role_id",
        info={
            "colanderalchemy": {
                "title": _("Settings role"),
                "exclude": True
            }
        },
    )

    roles = relationship(
        Role,
        secondary=user_role,
        secondaryjoin=Role.id == user_role.c.role_id,
        backref=backref(
            "users",
            order_by="User.username",
            info={
                "colanderalchemy": {
                    "title": _("Users"),
                    "description": _("Users granted with this role."),
                    "exclude": True,
                }
            },
        ),
        info={
            "colanderalchemy": {
                "title": _("Roles"),
                "description": _("Roles granted to the user."),
                "exclude": True,
            }
        },
    )

    last_login = Column(
        DateTime(timezone=True),
        info={
            "colanderalchemy": {
                "title": _("Last login"),
                "description": _("Date of the user's last login."),
                "missing": drop,
                "widget": DateTimeInputWidget(readonly=True),
            }
        },
    )

    expire_on = Column(
        DateTime(timezone=True),
        info={
            "colanderalchemy": {
                "title":
                _("Expiration date"),
                "description":
                _("After this date the user will not be able to login anymore."
                  ),
            }
        },
    )

    deactivated = Column(
        Boolean,
        default=False,
        info={
            "colanderalchemy": {
                "title":
                _("Deactivated"),
                "description":
                _("Deactivate a user without removing it completely."),
            }
        },
    )

    def __init__(  # nosec
        self,
        username: str = "",
        password: str = "",
        email: str = "",
        is_password_changed: bool = False,
        settings_role: Optional[Role] = None,
        roles: Optional[List[Role]] = None,
        expire_on: Optional[datetime] = None,
        deactivated: bool = False,
    ) -> None:
        self.username = username
        self.password = password
        self.tech_data = {}
        self.email = email
        self.is_password_changed = is_password_changed
        if settings_role:
            self.settings_role = settings_role
        self.roles = roles or []
        self.expire_on = expire_on
        self.deactivated = deactivated

    @property
    def password(self) -> str:
        """Get the password."""
        return self._password  # type: ignore

    @password.setter
    def password(self, password: str) -> None:
        """Encrypt password on the fly."""
        self._password = self.__encrypt_password(password)

    def set_temp_password(self, password: str) -> None:
        """Encrypt password on the fly."""
        self.temp_password = self.__encrypt_password(password)

    @staticmethod
    def __encrypt_password_legacy(password: str) -> str:
        """Hash the given password with SHA1."""
        return sha1(password.encode("utf8")).hexdigest()  # nosec

    @staticmethod
    def __encrypt_password(password: str) -> str:
        return crypt.crypt(password, crypt.METHOD_SHA512)

    def validate_password(self, passwd: str) -> bool:
        """
        Check the password against existing credentials. this method _MUST_ return a boolean.

        @param passwd: the password that was provided by the user to
        try and authenticate. This is the clear text version that we will
        need to match against the (possibly) encrypted one in the database.
        """
        if self._password.startswith("$"):
            # new encryption method
            if compare_hash(self._password,
                            crypt.crypt(passwd, self._password)):
                return True
        else:
            # legacy encryption method
            if compare_hash(self._password,
                            self.__encrypt_password_legacy(passwd)):
                # convert to the new encryption method
                self._password = self.__encrypt_password(passwd)
                return True

        if (self.temp_password is not None
                and self.temp_password != ""  # nosec
                and compare_hash(self.temp_password,
                                 crypt.crypt(passwd, self.temp_password))):
            self._password = self.temp_password
            self.temp_password = None
            self.is_password_changed = False
            return True
        return False

    def expired(self) -> bool:
        return self.expire_on is not None and self.expire_on < datetime.now(
            pytz.utc)

    def update_last_login(self) -> None:
        self.last_login = datetime.now(pytz.utc)

    def __str__(self) -> str:
        return self.username or ""