class HttpPush(db_sql.Model): __tablename__ = 'http_push' __table_args__ = {'schema': 'nwkserver'} app_eui = db_sql.Column(BINARY(8), ForeignKey(Application.app_eui, ondelete='CASCADE', onupdate='CASCADE'), primary_key=True) url = db_sql.Column(String(200), nullable=False) def obj_to_dict(self): return {'open': True, 'url': self.url} def add(self): db_sql.session.add(self) db_sql.session.commit() def delete(self): db_sql.session.delete(self) db_sql.session.commit() def update(self): db_sql.session.commit()
class Role(db.Model): __bind_key__ = 'lorawan' __table_args__ = {'schema': 'lorawan'} __tablename__ = 'role' id = db.Column(db.Integer(), primary_key=True) name = db.Column(db.String(50), unique=True)
class UserRoles(db.Model): __bind_key__ = 'lorawan' __tablename__ = 'user_roles' __table_args__ = {'schema': 'lorawan'} db.Column(db.Integer(), primary_key=True) user_id = db.Column(db.Integer(), db.ForeignKey('lorawan.user.id', ondelete='CASCADE')) role_id = db.Column(db.Integer(), db.ForeignKey('lorawan.role.id', ondelete='CASCADE')) PrimaryKeyConstraint(user_id, role_id)
class Token(db.Model): __bind_key__ = 'lorawan' __table_args__ = {'schema': 'lorawan'} id = db.Column(db.Integer, primary_key=True) client_id = db.Column( db.String(40), db.ForeignKey(Client.client_id), nullable=False, ) client = db.relationship('Client') user_id = db.Column(db.Integer, db.ForeignKey(User.id)) user = db.relationship('User') # currently only bearer is supported token_type = db.Column(db.String(40)) access_token = db.Column(db.String(255), unique=True) refresh_token = db.Column(db.String(255), unique=True) expires = db.Column(db.DateTime) _scopes = db.Column(db.Text) def delete(self): db.session.delete(self) db.session.commit() return self @property def scopes(self): if self._scopes: return self._scopes.split() return []
class UserInvitation(db.Model): __bind_key__ = 'lorawan' __tablename__ = 'user_invite' __table_args__ = {'schema': 'lorawan'} id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(255)) # save the user of the invitee invited_by_user_id = db.Column(db.Integer, db.ForeignKey('lorawan.user.id')) # token used for registration page to identify user registering token = db.Column(db.String(100), nullable=False, server_default='') used_by = db.Column(db.Integer, db.ForeignKey('lorawan.user.id')) create_at = db.Column(db.DateTime(), nullable=False) expired = db.Column(db.Boolean())
class Gateway(db_sql.Model): redis_fields = (Field.user_id, Field.platform, Field.model, Field.freq_plan, Field.public, Field.disable, Field.location) __vars_can_write = (Field.platform, Field.model, Field.freq_plan, Field.public, Field.disable, Field.name, Field.location) _assert_switcher = { Field.user_id: Assertions.a_not_negative_int, Field.id: Assertions.a_eui_64, Field.mac_addr: Assertions.a_eui_48, Field.name: Assertions.a_str, Field.platform: Platform.assert_isinstanceof, Field.freq_plan: FrequencyPlan.assert_isinstanceof, Field.model: Model.assert_isinstanceof, Field.public: Assertions.a_bool, Field.disable: Assertions.a_bool, Field.restart: Assertions.a_bool, Field.location: Location.assert_isinstanceof, Field.time: Assertions.a_int, } __table_args__ = {'schema': 'nwkserver'} __tablename__ = 'gateway' id = Column(BINARY(8), primary_key=True) name = Column(String(50)) user_id = db_sql.Column(db_sql.Integer(), ForeignKey(User.id, ondelete='CASCADE', onupdate='CASCADE'), nullable=False) @orm.reconstructor def init_on_load(self): self.mac_addr = eui_64_to_48(self.id) info = db0.hgetall(ConstDB.gateway + hexlify(self.id).decode()) self.freq_plan = FrequencyPlan(info[b'freq_plan'].decode()) self.public = bool(int(info[b'public'])) self.disable = bool(int(info[b'disable'])) self.platform = Platform[info[b'platform'].decode()] self.model = Model[info[b'model'].decode()] location = info.get(b'location') if location is not None: self.location = Location.objects.str_to_obj(location.decode()) else: self.location = Location(0.0, 0.0, 0) time = db3.get(ConstDB3.T_GATEWAY + hexlify(self.id).decode()) if time is not None: self.time = int(time) def __setattr__(self, key, value): try: attr = getattr(self, key) if attr is not None and key not in self.__vars_can_write: raise ReadOnlyDeny except AttributeError: pass if key in self._assert_switcher: self._assert_switcher[key](value) super.__setattr__(self, key, value) def __init__(self, user_id, mac_addr, name, platform, model, freq_plan=FrequencyPlan.EU863_870, public=True, disable=False, location=None): """ :param id: 8 bytes :param name: str :param platform: Platform :return: """ self.user_id = user_id self.id = eui_48_to_64(mac_addr) self.name = name self.platform = platform self.freq_plan = freq_plan self.public = public self.disable = disable self.model = model if location is not None: self.location = location else: self.location = Location(0.0, 0.0, 0) def _zip_vars(self): return dict( zip(self.redis_fields, (self.user_id, self.platform.name, self.model.name, self.freq_plan.value, self.public.real, self.disable.real, str(self.location)))) def _zip_vars_can_write(self): dd = {} for field in self.redis_fields: if field in self.__vars_can_write: value = getattr(self, field) if isinstance(value, enum.Enum): value = value.value if field == Field.freq_plan else value.name elif isinstance(value, bool): value = value.real dd[field] = value return dd def send_restart_request(self): db0.hset(ConstDB.gateway + hexlify(self.id).decode(), 'restart', 1) def save(self): db_sql.session.add(self) id_str = hexlify(self.id).decode() key = ConstDB.gateway + id_str if db0.exists(key): raise KeyDuplicateError(key) db0.hmset(key, self._zip_vars()) #save to sql db_sql.session.commit() db_sql.session.registry.clear() def update(self): print(self._zip_vars_can_write()) db0.hmset(ConstDB.gateway + hexlify(self.id).decode(), self._zip_vars_can_write()) db_sql.session.commit() def delete(self): db_sql.session.delete(self) db_sql.session.commit() # delete from sql id = hexlify(self.id).decode() gateway_trans = db0.keys(pattern=ConstDB.trans_params + '*' + id) pipe = db0.pipeline() for key in gateway_trans: key = key.decode() pipe.delete(key) dev_eui = key.split(":")[1] pipe.zrem(ConstDB.dev_gateways + dev_eui, self.id) pipe.delete(ConstDB.gateway + id) pipe.delete(ConstDB.gateway_pull + id) pipe.execute() def obj_to_dict(self): dd = { 'id': hexlify(self.id).decode().upper(), 'mac_addr': hexlify(self.mac_addr).decode().upper(), 'name': self.name, 'platform': self.platform.value, 'model': self.model.value, 'freq_plan': self.freq_plan.value, 'public': self.public, 'disable': self.disable, 'location': self.location.obj_to_dict(), } if hasattr(self, 'time'): dd['last_data'] = self.time self.get_pull_info() if hasattr(self, 'ip_addr'): dd['ip'] = self.ip_addr if hasattr(self, 'prot_ver'): dd['ver'] = self.prot_ver return dd def get_pull_info(self): key = ConstDB.gateway_pull + hexlify(self.id).decode() info = db0.hgetall(key) if info: self.ip_addr = info[b'ip_addr'].decode() self.prot_ver = int(info[b'prot_ver'])
class LocationService(db_sql.Model): __tablename__ = 'location_service' __table_args__ = {'schema': 'nwkserver'} app_eui = db_sql.Column(BINARY(8), ForeignKey(Application.app_eui, ondelete='CASCADE', onupdate='CASCADE'), primary_key=True) def delete(self): db_sql.session.delete(self) db_sql.session.commit() def add(self): db_sql.session.add(self) db_sql.session.commit() # class ServiceName(enum.Enum): # http_push = 'http push' # location = 'location' # # # class Service(db_sql.Model): # __tablename__ = 'service' # # @declared_attr # def __table_args__(cls): # return {'schema': find_schema(cls)} # # id = db_sql.Column(db_sql.Integer(), primary_key=True) # name = db_sql.Column(Enum(ServiceName), unique=True) # # def obj_to_dict(self): # return {'name': self.name} # # # class AppServices(db_sql.Model): # __tablename__ = 'app_services' # # @declared_attr # def __table_args__(cls): # return {'schema': find_schema(cls)} # # app_eui = db_sql.Column(BINARY(8), db_sql.ForeignKey('nwkserver.app.app_eui', ondelete='CASCADE')) # service_id = db_sql.Column(db_sql.Integer(), db_sql.ForeignKey('nwkserver.service.id', ondelete='CASCADE')) # PrimaryKeyConstraint(app_eui, service_id) # info = db_sql.Column(db_sql.String(200), nullable=True) # service = db_sql.relationship('Service') # # def obj_to_dict(self): # return {'name': self.service.name, # 'info': self.info} # # def delete(self): # db_sql.session.delete(self) # db_sql.session.commit() # # def get(self, app_eui, service_name): # q = db_sql.session.query(AppServices).filter(AppServices.app_eui == app_eui).join(AppServices.service).filter(Service.name==service_name).first() # return q
class User(db.Model): __bind_key__ = 'lorawan' __table_args__ = {'schema': 'lorawan'} __tablename__ = 'user' id = db.Column(db.Integer, primary_key=True) # User email information email = db.Column(db.String(255), nullable=False, unique=True) # User authentication information password = db.Column(db.String(255), nullable=False, server_default='') reset_password_token = db.Column(db.String(100), nullable=True) confirmed_at = db.Column(db.DateTime()) confirm_email_token = db.Column(db.String(100), nullable=True) # User information active = db.Column('is_active', db.Boolean(), nullable=False, server_default='0') first_name = db.Column(db.String(100), nullable=True) last_name = db.Column(db.String(100), nullable=True) # Relationships roles = relationship('Role', secondary='lorawan.user_roles') apps = relationship('Application') gateways = relationship('Gateway') def generate_auth_token(self, expiration=600): s = Serializer(current_app.config['SECRET_KEY'], expires_in=expiration) return s.dumps({'id': self.id}) @staticmethod def verify_auth_token(token): s = Serializer(current_app.config['SECRET_KEY']) try: data = s.loads(token) except SignatureExpired: return None # valid token, but expired except BadSignature: return None # invalid token user = User.query.get(data['id']) return user def verify_password(self, password): """ Make it backward compatible to legacy password hash. In addition, if such password were found, update the user's password field. """ hashed_password = self.password verified = passwords.verify_password(current_app.user_manager, password, hashed_password) return verified def role_name_list(self): name_list = [] for role in self.roles: name_list.append(role.name) return name_list def obj_to_dict(self): return { 'id': self.id, 'email': self.email, 'roles': self.role_name_list(), 'confirmed_at': str(self.confirmed_at), 'active': str(self.active), 'app_num': self.apps.__len__(), 'gateway_num': self.gateways.__len__() }