diff --git a/README.md b/README.md
index 8068dce..cb08a77 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,11 @@
+
+CELCOMBiller
+============
+
+CELCOMBiller is an open source biller system to *OpenBTS* and *Asterisk*
+
+
+
# Used third-party libraries
* pyst
@@ -10,7 +18,7 @@
```bash
$ virtualenv -p /usr/bin/python2.7 venv
$ source venv/bin/activate
-$ pip install --allow-external pyst --allow-unverified pyst -r requirements.txt
+$ pip install --allow-external --allow-unverified -r requirements.txt
```
## Database setup
@@ -21,13 +29,14 @@ Each SIP user must be inserted in the database of users with a balance. The pyth
from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy
from config import db
-from models import User
+from models import User, Ballance
-admin = User('admin', 'adm123', '999999999', '9999', True)
-guest = User('guest', '123123', '999999999', '0000', False)
+admin = User(True,'administrator', 'nowhere', '000','admin', 'adm123', '999999999','999999999999999', '0' ,'0')
+guest = User(True,'guest', 'nowhere', '1','guest', '123123', '999999998','999999999999998', '0' ,'0')
db.session.add(admin)
db.session.add(guest)
+
db.session.commit()
```
@@ -41,7 +50,7 @@ To test the api we will use curl
###USER
-login is required to test:
+you must login before test the api:
```bash
curl -c cookiefile -d "username=admin&password=adm123" -X POST -s http://localhost:5000/login
@@ -50,25 +59,31 @@ curl -c cookiefile -d "username=admin&password=adm123" -X POST -s http://localho
now to add user:
```bash
-curl -b cookiefile -H "Content-Type: application/json" -X POST -d '{"username":"yourusername","password":"yourpassword","clid":"999999999","imsi":"12345678900" "admin":'false'}' -s http://localhost:5000/api/users
+curl -b cookiefile -H "Content-Type: application/json" -X POST -d '{"username":"yourusername","password":"yourpassword","clid":"999999999","imsi":"12345678900", "admin":'false', "name":"administrator","adress":"lasse","cpf":"000","voice_balance":"0","data_balance":"0"}' -s http://localhost:5000/api/users
```
the balance came by another table, so we want add balance to user we need run:
-add balance:
+add/remove data balance:
```bash
-curl -b cookiefile -H "Content-Type: application/json" -X POST -d '{"signal":"+", "type_":"increase", "value": "1000", "userId":1}' -s http://localhost:5000/api/balance
+curl -b cookiefile -H "Content-Type: application/json" -X POST -d '{"value": "1000", "user_id":3,"origin":"web"}' -s http://localhost:5000/api/data_balance
+
#note that userId need some user id, in that case we use 1
+#to remove balance the value must be negative
```
-remove balance:
+add/remove voice balance:
```bash
-curl -b cookiefile -H "Content-Type: application/json" -X POST -d '{"signal":"+", "type_":"increase", "value": "1000", "userId":1}' -s http://localhost:5000/api/balance
+curl -b cookiefile -H "Content-Type: application/json" -X POST -d '{"value": "1000", "userId":1}' -s http://localhost:5000/api/voice_balance
+
+#note that userId need some user id, in that case we use 1
+#to remove balance the value must be negative
```
+
update user
```bash
@@ -81,18 +96,18 @@ remove user
curl -X DELETE -s http://localhost:5000/api/users/yourusername -b cookiefile
```
-###GROUPS
+###Schedule
add group
```bash
-curl -X POST -H "Content-Type: application/json" -d '{"name":"group_name","day":1, "month":1, "year":3000, "count":10, "users":[id_]}' -s http://localhost:5000/api/groups
+curl -X POST -H "Content-Type: application/json" -d '{"name":"group_name","day":1, "month":1, "year":3000, "count":10}' -s http://localhost:5000/api/schedules
```
update group
```bash
-curl -X PATCH -H "Content-Type: application/json" -d '{}' -s http://localost:5000/api/groups/group_name
+curl -X PATCH -H "Content-Type: application/json" -d '{}' -s http://localost:5000/api/schedules/schedule
```
@@ -145,25 +160,7 @@ celcombiller_reducer
```
+## Upstart
-
-You dont need to write a constructor, you can either treat the addresses property on a Person instance as a list:
-
-a = Address(email='foo@bar.com')
-p = Person(name='foo')
-p.addresses.append(a)
-
-Or you can pass a list of addresses to the Person constructor
-
-a = Address(email='foo@bar.com')
-p = Person(name='foo', addresses=[a])
-
-In either case you can then access the addresses on your Person instance like so:
-
-db.session.add(p)
-db.session.add(a)
-db.session.commit()
-print p.addresses.count() # 1
-print p.addresses[0] #
-print p.addresses.filter_by(email='foo@bar.com').count() # 1
+To have Celcombiler running as a service you have to modify the file celcombiller.conf and put it in your /etc/init directory.
diff --git a/adduser.py b/adduser.py
index f6341ac..392ca9c 100644
--- a/adduser.py
+++ b/adduser.py
@@ -1,11 +1,13 @@
-from flask import Flask
-from flask.ext.sqlalchemy import SQLAlchemy
from config import db
-from models import User, Ballance
+from models import User
-admin = User('admin', 'adm123', '999999999', True,'999999999999999')
-guest = User('guest', '123123', '999999998', False,'000000000000000')
+
+admin = User('0', 'administrator', '000', 'admin', 'adm123',
+ '999999999', '999999999999999', '0', '0', 'nowhere')
+guest = User('3', 'guest', '1', 'guest', '123123', '999999998',
+ '999999999999998', '0', '0', 'nowhere')
db.session.add(admin)
db.session.add(guest)
+
db.session.commit()
diff --git a/app.py b/app.py
old mode 100644
new mode 100755
index 2308a3b..10b4335
--- a/app.py
+++ b/app.py
@@ -1,27 +1,37 @@
import flask
-from flask import Flask, session, request, flash, url_for, redirect, \
- render_template, abort
+from flask import request, flash, render_template
from config import db, app, login_manager
-from models import CDR, User, Groups, Dates, Ballance
-from time import strftime
+from models import User, VoiceBalance, DataBalance, Schedules, ScheduleInput, \
+ ScheduleUser
from datetime import *
from dateutil.rrule import *
from dateutil.parser import *
from dateutil.relativedelta import *
from flask_restless import ProcessingException
-from flask.ext.login import login_user , logout_user , current_user ,\
+from flask.ext.login import login_user, logout_user, current_user,\
login_required
import json
from openbts import to_openbts
+
@app.route('/')
def index():
"""
Index page, just show the logged username
"""
- return render_template('index.html')
+ try:
+ if current_user.is_authenticated():
+ return render_template('index.html')
+ else:
+ return "no else"
+ except Exception:
+ return render_template('anonymous.html')
+@app.route('/test',methods=['GET'])
+def test():
+ return "rodou"
+# Login, if the user does not exist it returs a error page
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
@@ -34,68 +44,105 @@ def login():
if registered_user is None:
flash('Username or Password is invalid', 'error')
return render_template('ERROR.html')
- login_user(registered_user)
- json_with_names = check_time()
- return "Hello, cross-origin-world!"
-
-def check_time():
- if not current_user.is_admin():
- return False
- else:
- json_need_update = []
- groups = Groups.query.all()
- for group in groups:
- boolean_time = (group.dates_to_update[0].date - datetime.now())\
- .total_seconds()
- boolean_time = 1 if boolean_time < 0 else 0
- if boolean_time == 1:
- json_need_update.append(group.name)
- if json_need_update == []:
- return None
+ if login_user(registered_user):
+ return "Hello, cross-origin-world!"
else:
- return json_need_update
+ flash('Flask Login error', 'error')
+ return render_template('ERROR.html')
+ # json_with_names = check_time()
-def already_has_group(data=None, **kargs):
+# Returns the user data balance
+@app.route('/check_data_balance', methods=['GET', 'POST'])
+def check_data_balance(*args, **kargs):
data = request.data
request_body = json.loads(data)
- group = Groups.query.\
- filter_by(name=request_body['name']).first()
- if group is not None:
- raise ProcessingException(description='Already has this Group', code=400)
- else:
- pass
+ # Is it a better way to handle the exception when the user is not found ?
+ try:
+ x = User.query.filter_by(
+ imsi=request_body['imsi']).first().DataBalance()
+ return str(x)
+ except AttributeError:
+ return "none"
+
+# Returns the user voice balance
-def put_user_id_in_buffer(*args, **kargs):
- data = request.data
- request_body = json.loads(data)
- global buffer_usersId
- buffer_usersId = request_body['users']
- del kargs['data']['users']
-def add_users_to_group(*args, **kargs):
- global buffer_usersId
+@app.route('/check_voice_balance', methods=['GET', 'POST'])
+def check_voice_balance(*args, **kargs):
data = request.data
request_body = json.loads(data)
- group = Groups.query\
- .filter_by(name=request_body['name']).first()
- for userId in buffer_usersId:
- user = User.query.filter_by(id_=userId).first()
- group.tunel.append(user)
- db.session.add(group)
- db.session.commit()
- pass
-
-def add_dates_to_group(*args, **kargs):
- global data_count
+ # Is it a better way to handle the exception when the user is not found ?
+ try:
+ x = User.query.filter_by(
+ imsi=request_body['imsi']).first().VoiceBalance()
+ return str(x)
+ except AttributeError:
+ return "none"
+
+
+# I dont know what this function does so I commented it.
+# def check_time():
+# if not current_user.is_admin():
+# return False
+# else:
+# json_need_update = []
+# schedules = Schedules.query.all()
+# for schedule in schedules:
+# boolean_time = (schedule.dates_to_update[0].date - datetime.now())\
+# .total_seconds()
+# boolean_time = 1 if boolean_time < 0 else 0
+# if boolean_time == 1:
+# json_need_update.append(schedule.name)
+# if json_need_update == []:
+# return None
+# else:
+# return json_need_update
+
+# Check if the user has a schedule
+def schedule_exists(data=None, **kargs):
data = request.data
request_body = json.loads(data)
- group = Groups.query.\
+ schedule = Schedules.query.\
filter_by(name=request_body['name']).first()
- listOfdates = Dates.query.order_by(Dates.id_.desc()).limit(data_count)
- for date in listOfdates:
- group.dates_to_update.append(date)
- pass
+ if schedule is not None:
+ raise ProcessingException(
+ description='A schedule with this name already exists', code=400)
+ else:
+ pass
+
+# Let's put onlt one user at time in the schedule
+# def put_user__idin_buffer(*args, **kargs):
+# data = request.data
+# request_body = json.loads(data)
+# global buffer_users_id
+# buffer_users_id = request_body['users']
+# del kargs['data']['users']
+
+# def add_users_to_schedule(*args, **kargs):
+# global buffer_users_id
+# data = request.data
+# request_body = json.loads(data)
+# schedule = Schedules.query\
+# .filter_by(name=request_body['name']).first()
+# #for user_id in buffer_users_id:
+# user = User.query.filter_by(_id=user_id).first()
+# schedule.tunel.append(user)
+# db.session.add(schedule)
+# db.session.commit()
+# pass
+
+# def add_dates_to_schedule(*args, **kargs):
+# global data_count
+# data = request.data
+# request_body = json.loads(data)
+# schedule = Schedules.query.\
+# filter_by(name=request_body['name']).first()
+# listOfdates = Dates.query.order_by(Dates._id.desc()).limit(data_count)
+# for date in listOfdates:
+# schedule.dates_to_update.append(date)
+# pass
+
def transform_to_utc(*args, **kargs):
global data_count
@@ -110,7 +157,7 @@ def transform_to_utc(*args, **kargs):
month = int(request_body['month'])
how_many = int(request_body['count'])
if year < min_year or ((month < min_month) and (year <= min_year)) or \
- (day < min_day and (month <= min_month and year <= min_year)):
+ (day < min_day and (month <= min_month and year <= min_year)):
raise ProcessingException(description='Date not accept', code=400)
else:
del kargs['data']['day']
@@ -125,22 +172,42 @@ def transform_to_utc(*args, **kargs):
db.session.commit()
pass
-def date_now(*args, **kargs):
- kargs['data']['date'] = unicode(datetime.now())
- global buffer_usersId
- buffer_usersId = kargs['data']['userId']
- del kargs['data']['userId']
+# def date_now(*args, **kargs):
+# kargs['data']['date'] = unicode(datetime.now())
+# global buffer_users_id
+# buffer_users_id = kargs['data']['user_id']
+# #del kargs['data']['user_id']
+
-def add_user_balance(*args, **kargs):
- global buffer_usersId
+def add_user_data_balance(*args, **kargs):
+ global buffer_users_id
data = request.data
request_body = json.loads(data)
- request_body['userId']
- x = Ballance.query.order_by(Ballance.id_.desc()).first()
- x.usersId = request_body['userId']
+ # Check if we are passing the user id or the imsi in the user_id field, it
+ # is necessary because Openbts users IMSI only.
+ if request_body['user_id'] < 1e13:
+ x = DataBalance.query.order_by(DataBalance._id.desc()).first()
+ x.users_id = request_body['user_id']
+ else:
+ x = DataBalance.query.order_by(Balance._id.desc()).first()
+ x.users_id = User.query.filter_by(
+ imsi=request_body['user_id']).first()._id
db.session.add(x)
db.session.commit()
+
+def add_user_voice_balance(*args, **kargs):
+ global buffer_users_id
+ data = request.data
+ request_body = json.loads(data)
+
+ x = VoiceBalance.query.order_by(VoiceBalance._id.desc()).first()
+ x.users_id = request_body['from_user_id']
+
+ db.session.add(x)
+ db.session.commit()
+
+
@app.route('/logout')
def logout():
logout_user()
@@ -148,8 +215,8 @@ def logout():
@login_manager.user_loader
-def load_user(id_):
- return User.query.get(int(id_))
+def load_user(_id):
+ return User.query.get(int(_id))
@app.route('/check')
@@ -161,23 +228,33 @@ def check_login():
return render_template('check.html')
+@app.route('/checkadm')
+def checkadm():
+ """
+ Index page, just show the logged username
+ """
+
+ return str(current_user)
+
+
def auth(*args, **kargs):
"""
Required API request to be authenticated
"""
- if not current_user.is_authenticated():
- raise ProcessingException(description='Not authenticated', code=401)
+ #if not current_user.is_authenticated():
+ # raise ProcessingException(description='Not authenticated', code=401)
+ pass
def preprocessor_check_adm(*args, **kargs):
- if not current_user.is_admin():
- raise ProcessingException(description='Forbidden', code=403)
-
+ # if not current_user.is_admin():
+ # raise ProcessingException(description='Forbidden', code=403)
+ pass
def preprocessors_patch(instance_id=None, data=None, **kargs):
- user_cant_change = ["admin", "clid", "id_",
- "originated_calls", "received_calls, tunel"]
- admin_cant_change = ["id_", "originated_calls", "received_calls"]
+ user_cant_change = ["level", "clid", "_id",
+ "originated_calls", "received_calls"]
+ admin_cant_change = ["_id", "originated_calls", "received_calls"]
if current_user.is_admin():
for x in data.keys():
if x in admin_cant_change:
@@ -197,23 +274,23 @@ def preprocessors_check_adm_or_normal_user(instance_id=None, **kargs):
manager = flask.ext.restless.APIManager(app, flask_sqlalchemy_db=db)
# Create the Flask-Restless API manager.
-# Create API endpoints, which will be available at /api/ by
+# Create API endpoints, which will be available at /pi/ by
# default. Allowed HTTP methods can be specified as well.
manager.create_api(
User,
preprocessors={
'POST': [
- auth,
- preprocessor_check_adm
+ # auth,
+ # preprocessor_check_adm
],
'GET_MANY': [
- auth,
- preprocessor_check_adm
+ # auth,
+ # preprocessor_check_adm
],
'GET_SINGLE': [
- auth,
- preprocessors_check_adm_or_normal_user
+ # auth,
+ # preprocessors_check_adm_or_normal_user
],
'PATCH_SINGLE': [
auth,
@@ -223,9 +300,9 @@ def preprocessors_check_adm_or_normal_user(instance_id=None, **kargs):
'PATCH_MANY': [auth, preprocessor_check_adm],
'DELETE_SINGLE': [auth, preprocessor_check_adm],
},
- postprocessors={
- 'POST':[to_openbts]
- },
+ postprocessors={
+ 'POST': [to_openbts]
+ },
exclude_columns=[
'password'
],
@@ -235,35 +312,71 @@ def preprocessors_check_adm_or_normal_user(instance_id=None, **kargs):
)
manager.create_api(
- CDR,
+ Schedules,
preprocessors={
'POST': [
+ # auth,
+ # preprocessor_check_adm,
+ # schedule_exists,
+ # put_user__idin_buffer,
+ transform_to_utc
+ ],
+ 'GET_MANY': [
auth,
preprocessor_check_adm
],
+ 'GET_SINGLE': [auth, preprocessor_check_adm],
+ 'PATCH_SINGLE': [
+ auth,
+ preprocessor_check_adm
+ ],
+ 'DELETE_SINGLE': [auth, preprocessor_check_adm],
+ },
+ postprocessors={
+ # 'POST': [add_dates_to_schedule, add_users_to_schedule],
+ 'POST': [],
+ },
+ exclude_columns=[
+ 'newUser',
+ 'removeUser',
+ 'updateSchedule'
+ ],
+ methods=['POST', 'GET', 'PATCH', 'DELETE'],
+ results_per_page=100
+)
+
+manager.create_api(
+ ScheduleUser,
+ preprocessors={
+ 'POST': [
+ preprocessor_check_adm,
+ # date_now
+ ],
'GET_MANY': [
auth,
preprocessor_check_adm
],
- 'GET_SINGLE': [
+ 'GET_SINGLE': [auth, preprocessor_check_adm],
+ 'PATCH_SINGLE': [
auth,
- preprocessors_check_adm_or_normal_user
+ preprocessor_check_adm
],
- 'PATCH_SINGLE': [auth, preprocessors_patch],
'DELETE_SINGLE': [auth, preprocessor_check_adm],
},
- methods=['POST','GET','PATCH', 'DELETE']
+ postprocessors={
+ 'POST': []
+ },
+ methods=['POST', 'GET', 'PATCH', 'DELETE'],
+ results_per_page=100,
)
+
manager.create_api(
- Groups,
+ VoiceBalance,
preprocessors={
'POST': [
- auth,
- preprocessor_check_adm,
- already_has_group,
- put_user_id_in_buffer,
- transform_to_utc
+ #preprocessor_check_adm,
+ # date_now
],
'GET_MANY': [
auth,
@@ -277,24 +390,18 @@ def preprocessors_check_adm_or_normal_user(instance_id=None, **kargs):
'DELETE_SINGLE': [auth, preprocessor_check_adm],
},
postprocessors={
- 'POST': [add_dates_to_group, add_users_to_group],
+ 'POST': [add_user_voice_balance]
},
- exclude_columns=[
- 'newUser',
- 'removeUser',
- 'updateGroup'
- ],
methods=['POST', 'GET', 'PATCH', 'DELETE'],
results_per_page=100,
- primary_key='name'
)
manager.create_api(
- Ballance,
+ DataBalance,
preprocessors={
'POST': [
- preprocessor_check_adm,
- date_now
+ # preprocessor_check_adm,
+ # date_now
],
'GET_MANY': [
auth,
@@ -308,12 +415,13 @@ def preprocessors_check_adm_or_normal_user(instance_id=None, **kargs):
'DELETE_SINGLE': [auth, preprocessor_check_adm],
},
postprocessors={
- 'POST': [add_user_balance]
+ 'POST': [add_user_data_balance]
},
methods=['POST', 'GET', 'PATCH', 'DELETE'],
results_per_page=100,
)
+
# start the flask loop
app.debug = True
app.run('0.0.0.0', 5000)
diff --git a/celcombiller-backend.conf b/celcombiller-backend.conf
new file mode 100644
index 0000000..2ce02d6
--- /dev/null
+++ b/celcombiller-backend.conf
@@ -0,0 +1,21 @@
+# CELCOMBiller
+#
+# This service runs celcombiller backend from the point the system is
+# started until it is shut down again.
+# on ubuntu you have to put this file in /etc/init
+#
+start on runlevel [2345]
+
+respawn
+
+script
+ /path_to_venv/venv/bin/python /path_to_celcombiller/celcombiller/app.py
+end script
+
+pre-start script
+
+ touch /path_to_db/alph.db
+
+ chmod 666 /path_to_db/alph.db
+
+end script
diff --git a/celcombiller-frontend.conf b/celcombiller-frontend.conf
new file mode 100644
index 0000000..31eb642
--- /dev/null
+++ b/celcombiller-frontend.conf
@@ -0,0 +1,14 @@
+# CELCOMBiller
+#
+# This service runs celcombiller-frontend from the point the system is
+# started until it is shut down again.
+# on ubuntu you have to put this file in /etc/init
+#
+start on runlevel [2345]
+
+respawn
+
+script
+ exec /path_to_gulp/gulp -gulpfile /path_to_gulpfile/gulpfile.js
+end script
+
diff --git a/celcombiller_caller.py b/celcombiller_caller.py
index f29e7f6..7f233cf 100644
--- a/celcombiller_caller.py
+++ b/celcombiller_caller.py
@@ -19,8 +19,7 @@
try:
- agi.appexec('DIAL', 'SIP/IMSI%s@127.0.0.1:5062,40,S(%d)' %\
- (to_user.imsi, from_user.BallanceUser))
+ agi.appexec('DIAL', 'SIP/IMSI%s@127.0.0.1:5062,40,S(%d)' %
+ (to_user.imsi, from_user.VoiceBalance))
except AGIAppError:
pass
-
diff --git a/celcombiller_reducer.py b/celcombiller_reducer.py
index 48638eb..9c2cd69 100644
--- a/celcombiller_reducer.py
+++ b/celcombiller_reducer.py
@@ -8,14 +8,11 @@
# pylint: disable=C0103
from datetime import datetime
import asterisk.agi
-#from asterisk.agi import AGIAppError
from models import User
-
+from config import adm_user, adm_pssw
import requests
import json
-adm_user = 'admin'
-adm_pssw = 'adm123'
agi = asterisk.agi.AGI()
@@ -34,32 +31,23 @@
# Create a session
s = requests.Session()
# Login the session
- s.post('http://localhost:5000/login',\
- data={'username':adm_user, 'password': adm_pssw})
-
- # Create a new CDR record
- payload = '{"answer":"'+ str(answer)+'", "billsec":"'+ \
- str(billsec)+'", "from_user_id": '+\
- str(from_user.id_)+', "to_user_id":'+ str(to_user.id_)+'}'
-
- #Send the requestto update the user balance
- r = s.post('http://localhost:5000/api/cdr', json=json.loads(payload),\
- headers={'content-type': 'application/json'})
-
- #TODO: Handle when the request fail
- if r.ok == False:
- pass
-
- print from_user.id_
- payload = '{"signal":"-", "type_":"decrease", "value": "'+ str(billsec) +\
- '", "userId":'+ str(from_user.id_) +'}'
-
- # Send the requestto update the user balance
- r = s.post('http://localhost:5000/api/balance',\
- json=json.loads(payload),\
- headers={'content-type': 'application/json'})
-
- #TODO: Handle when the request fail
- if r.ok == False:
+ s.post(
+ 'http://localhost:5000/login',
+ data={'username': adm_user, 'password': adm_pssw}
+ )
+
+ payload = {'from_user_id':from_user.get_id,
+ 'to_user_id':to_user.get_id,
+ 'value':billsec*(-1),
+ 'origin':'call',
+ 'date':answer}
+
+ # Send the request to update the user balance
+ r = s.post('http://localhost:5000/api/voice_balance',
+ json=payload,
+ headers={'content-type': 'application/json'})
+
+ # TODO: Handle when the request fail
+ if r.ok is False:
pass
s.close()
diff --git a/config.py b/config.py
index 86ddca0..8fd61c2 100644
--- a/config.py
+++ b/config.py
@@ -2,11 +2,23 @@
import flask.ext.sqlalchemy
import flask.ext.restless
from flask.ext.login import LoginManager
+from flask.ext.cors import CORS
+
+# adm login and password
+adm_user = 'admin'
+adm_pssw = 'adm123'
+
+path_to_database = './alph.db'
+
# Create the Flask application and the Flask-SQLAlchemy object.
app = flask.Flask(__name__)
app.config['DEBUG'] = True
-app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/alph.db'
+app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///'+path_to_database
+
+
+# Ability cross domain
+cors = CORS(app)
db = flask.ext.sqlalchemy.SQLAlchemy(app)
diff --git a/docs/dastabase.png b/docs/dastabase.png
new file mode 100644
index 0000000..2991eaa
Binary files /dev/null and b/docs/dastabase.png differ
diff --git a/models.py b/models.py
index 0806b61..e4e2593 100644
--- a/models.py
+++ b/models.py
@@ -4,7 +4,8 @@
from sqlalchemy.dialects.postgresql import ENUM
from datetime import *
-row2dict = lambda r: {c.name: str(getattr(r, c.name)) for c in r.__table__.columns}
+row2dict = lambda r: {c.name: str(getattr(r, c.name))
+ for c in r.__table__.columns}
# Create your Flask-SQLALchemy models as usual but with the following two
# (reasonable) restrictions:
@@ -14,10 +15,6 @@
# all columns (the constructor in flask.ext.sqlalchemy.SQLAlchemy.Model
# supplies such a method, so you don't need to declare a new one).
-tunel_table = db.Table('association', db.Model.metadata,
- db.Column('User_id', db.Integer, db.ForeignKey('users.id_')),
- db.Column('Groups_id', db.Integer, db.ForeignKey('groups.id_'))
-)
class User(db.Model):
"""
@@ -25,16 +22,26 @@ class User(db.Model):
"""
__tablename__ = 'users'
- id_ = db.Column(db.Integer, primary_key=True)
- username = db.Column(db.Unicode, unique=True)
- password = db.Column(db.Integer)
- clid = db.Column(db.String(9), nullable=False, unique=True)
- admin = db.Column(db.Boolean)
- tunel = db.relationship('Groups', secondary=tunel_table)
- imsi = db.Column(db.Integer, unique=True)
-
+ _id = db.Column(db.Integer, primary_key=True, nullable=False)
+ level = db.Column(db.Integer, nullable=False) # 0=administrator, 1=users, 2=collaborator
+ name = db.Column(db.Unicode, nullable=False)
+ address = db.Column(db.Unicode)
+ cpf = db.Column(db.Integer, nullable=False, unique=True)
+ username = db.Column(db.Unicode, nullable=False, unique=True)
+ password = db.Column(db.Unicode, nullable=False)
+ clid = db.Column(db.Unicode(9), nullable=False, unique=True)
+ imsi = db.Column(db.Integer, nullable=False, unique=True)
+ voice_balance = db.Column(db.Integer, nullable=False)
+ data_balance = db.Column(db.Integer, nullable=False)
+
+ # ki = db.Column(db.Integer)
+ # city = db.Column(db.Unicode)
+ # state = db.Column(db.Unicode)
+ # postalcode = db.Column(db.Integer)
+ #
+
def is_admin(self):
- return self.admin
+ return (level==0 if True else False)
def is_authenticated(self):
return True
@@ -46,146 +53,176 @@ def is_anonymous(self):
return False
def get_id(self):
- return unicode(self.id_)
+ return self._id
+
+ def VoiceBalance(self):
+ return self.voice_balance
+
+ def DataBalance(self):
+ return self.data_balance
@hybrid_property
- def BallanceUser(self):
+ def VoiceBalanceHistoric(self):
# TODO: Maybe it should use object_session
- userBalanceNeg = Ballance.query.filter_by(usersId=self.id_).filter_by(signal=unicode('-'))
- userBalancePos = Ballance.query.filter_by(usersId=self.id_).filter_by(signal=unicode('+'))
- countNeg = 0
- countPos = 0
- for x in userBalanceNeg:
- countNeg = countNeg + x.value
- for x in userBalancePos:
- countPos = countPos + x.value
- return countPos - countNeg
+ balances = VoiceBalance.query.order_by(
+ VoiceBalance._id.desc()).filter_by(from_user_id=self._id).limit(10)
+ historic_list = []
+ for y in balances:
+ historic_list.append(row2dict(y))
+ return historic_list
@hybrid_property
- def BallanceUserHistoric(self):
+ def DataBalanceHistoric(self):
# TODO: Maybe it should use object_session
- balances = Ballance.query.order_by(Ballance.id_.desc()).filter_by(usersId=self.id_).limit(10)
+ balances = DataBalance.query.order_by(
+ DataBalance._id.desc()).filter_by(user_id=self._id).limit(10)
historic_list = []
for y in balances:
historic_list.append(row2dict(y))
-
return historic_list
- def __init__(self , username ,password, clid,admin, imsi ):
- self.username = username
- self.password = password
- self.clid = clid
- self.admin = admin
- self.imsi = imsi
+ def __init__(self, level, name, cpf, username, password, clid, imsi, voice_balance=None, data_balance=None, address=None):
+ self.level = level
+ self.name = name
+ self.address = address
+ self.cpf = cpf
+ self.username = username
+ self.password = password
+ self.clid = clid
+ self.imsi = imsi
+ self.voice_balance = voice_balance
+ self.data_balance = data_balance
def __repr__(self):
return '' % (self.username)
-class CDR(db.Model):
- """
- Call Detail Records holds information about finished calls
- """
- __tablename__ = 'cdr'
-
- id_ = db.Column(db.Integer, db.Sequence('cdr_id_seq'), primary_key=True)
- answer = db.Column(db.DateTime)
- billsec = db.Column(db.Integer)
- from_user_id = db.Column(db.Integer, db.ForeignKey('users.id_'))
- from_user = db.relationship('User', backref='originated_calls',
- foreign_keys=from_user_id)
- to_user_id = db.Column(db.Integer, db.ForeignKey('users.id_'))
- to_user = db.relationship('User', backref='received_calls',
- foreign_keys=to_user_id)
-
- def __repr__(self):
- return '' % (self.from_user, self.answer,
- self.billsec)
-class Groups(db.Model):
+class Schedules(db.Model):
"""
# Register Credits if
"""
- __tablename__ = 'groups'
+ __tablename__ = 'schedule'
- id_ = db.Column(db.Integer, primary_key=True)
+ _id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.Unicode)
- dates_to_update = db.relationship('Dates')
- tunel = db.relationship('User', secondary=tunel_table)
+ date = db.Column(db.DateTime)
- def __init__(self, name):
+ def __init__(self, name, date):
self.name = name
+ self.date = date
+
+ def __repr__(self):
+ return 'schedule %r' % (self.name)
+
+
+# this table is the association table between users and group in a
+# many-to-many relationship
+class ScheduleUser(db.Model):
+
+ __tablename__ = 'schedule_user'
+
+ user_id = db.Column(db.Integer, db.ForeignKey(
+ 'users._id'), primary_key=True)
+ group_id = db.Column(db.Integer, db.ForeignKey(
+ 'schedule._id'), primary_key=True)
+ count = db.Column(db.Integer, nullable=False)
+
+ def __init__(self, user_id, group_id, count):
+ self.user_id = user_id
+ self.group_id = group_id
+ self.count = count
def __repr__(self):
return 'GROUPS %r' % (self.name)
- @hybrid_property
- def newUser(self):
- return 0
- @newUser.setter
- def newUser(self, userIds):
- for userId in userIds:
- self.tunel.append(User.query.filter_by(id_=userId).first())
- db.session.add(self)
- db.session.commit()
+class VoiceBalance(db.Model):
+ """
+ Call Detail Records holds information about finished calls
+ """
+ __tablename__ = 'voice_balance'
+
+ _id = db.Column(db.Integer, db.Sequence('cdr_id_seq'), primary_key=True)
+ from_user_id = db.Column(
+ db.Integer, db.ForeignKey('users._id'), nullable=False)
+ to_user_id = db.Column(db.Integer, db.ForeignKey('users._id'))
+ value = db.Column(db.Integer)
+ date = db.Column(db.DateTime, nullable=False)
+ origin = db.Column(db.String, nullable=False)
+
+ # from_user = db.relationship('User', backref='originated_calls',
+ # foreign_keys=from_user_id)
+ # to_user = db.relationship('User', backref='received_calls',
+ # foreign_keys=to_user_id)
+
+ def __init__(self, from_user_id, value, origin, to_user_id=None, date=None):
+ self.from_user_id = from_user_id
+ self.to_user_id = to_user_id
+ self.value = value
+ self.origin = origin
+ if date is not None:
+ self.date = date
+ else:
+ self.date = datetime.now()
+
+ user = db.session.query(User).filter_by(_id=from_user_id).first()
+ user.voice_balance = user.voice_balance + int(value)
- @hybrid_property
- def removeUser(self):
- return 0
+ def __repr__(self):
+ return '' % (self.from_user, self.date,
+ self.value)
- @removeUser.setter
- def removeUser(self, userIds):
- for userId in userIds:
- self.tunel.remove(User.query.filter_by(id_=userId).first())
- @hybrid_property
- def updateGroup(self):
- return 0
+# this table register the user's voice balance
+class DataBalance(db.Model):
- @updateGroup.setter
- def updateGroup(self, check):
- if check == 1:
- deleteDate = Dates.query.filter_by(group_id=self.id_).first()
- db.session.delete(deleteDate)
- for var in self.tunel:
- db.session.query(User).filter_by(id_=var.id_)\
- .update({'balance':'1250'})
+ __tablename__ = 'data_balance'
-class Dates(db.Model):
+ _id = db.Column(db.Integer, primary_key=True)
+ user_id = db.Column(db.Integer, db.ForeignKey('users._id'))
+ date = db.Column(db.DateTime())
+ value = db.Column(db.Integer)
+ user_ip = db.Column(db.Unicode)
+ connection_ip = db.Column(db.Unicode)
+ origin = db.Column(db.Unicode, nullable=False)
- __tablename__ = 'dates'
+ def __init__(self, user_id, value, origin, user_ip=None, connection_ip=None, date=None):
- id_ = db.Column(db.Integer, primary_key=True)
- group_id = db.Column(db.Integer, db.ForeignKey('groups.id_'))
- date = db.Column(db.DateTime)
+ self.user_id = user_id
+ self.value = value
+ self.user_ip = user_ip
+ self.connection_ip = connection_ip
+ self.origin = origin
- def __init__(self, date):
- self.date = date
+ if date is not None:
+ self.date = date
+ else:
+ self.date = datetime.now()
+
+ user = db.session.query(User).filter_by(_id=user_id).first()
+ user.data_balance = user.data_balance + int(value)
def __repr__(self):
- return 'DATES %r' % (self.id_)
+ return 'data_balance %r' % (self._id)
-class Ballance(db.Model):
- __tablename__ = 'balance'
+class ScheduleInput(db.Model):
+ __tablename__ = 'schedule_input'
- id_ = db.Column(db.Integer, primary_key=True)
- usersId = db.Column(db.Integer, db.ForeignKey('users.id_'))
- date = db.Column(db.DateTime())
- type_ = db.Column(ENUM('increase', 'decrease'))
- value = db.Column(db.Integer)
- signal = db.Column(db.String(1))
+ _id = db.Column(db.Integer, primary_key=True)
+ schedule_id = db.Column(db.Integer, db.ForeignKey('schedule._id'))
+ voice_balance_id = db.Column(
+ db.Integer, db.ForeignKey('voice_balance._id'))
+ data_balance_id = db.Column(db.Integer, db.ForeignKey('data_balance._id'))
- def __init__(self, date, type_, value, signal, usersId=None):
- self.date = date
- self.type_ = type_
- self.value = value
- self.signal = signal
- if usersId is not None:
- self.usersId = usersId
+ def __init__(self, schedule_id, voice_balance_id, data_balance_id):
+ self.schedule_id = schedule_id
+ self.voice_balance_id = voice_balance_id
+ self.data_balance_id = data_balance_id
def __repr__(self):
- return 'balance %r' % (self.id_)
+ return 'schedule_input %r' % (self._id)
+
-# Create the database tables.
+# Create the database tablesself.
db.create_all()
diff --git a/openbts.py b/openbts.py
index d4fb787..df17642 100644
--- a/openbts.py
+++ b/openbts.py
@@ -1,30 +1,32 @@
-import sys
import zmq
+import json
+def to_openbts(result=None, **kw):
-def to_openbts(result = None, **kw):
+ for key, value in result.items():
+ if key == "_id":
+ _id = value
- id_ = ""
- clid = ""
- imsi = ""
+ elif key == "clid":
+ clid = value
- for key,value in result.items():
- if key == "id_":
- id_ = value
+ elif key == "imsi":
+ imsi = value
- elif key == "clid":
- clid = value
+ request = {
+ "command":"subscribers",
+ "action":"create",
+ "fields":{
+ "name": str(_id),
+ "imsi":"IMSI" + str(imsi),
+ "msisdn":str(clid) ,
+ "ki":""
+ }
+ }
- elif key == "imsi":
- imsi = value
-
- request = '{"command":"subscribers","action":"create","fields":{"name":"' + str(id_) + '","imsi":"IMSI' + str(imsi) + '","msisdn":"' + str(clid) + '","ki":""}}'
-
-
- context = zmq.Context()
- socket = context.socket(zmq.REQ)
- socket.connect("tcp://127.0.0.1:45064")
-
- socket.send(request)
+ context = zmq.Context()
+ socket = context.socket(zmq.REQ)
+ socket.connect("tcp://127.0.0.1:45064")
+ socket.send_string(json.dumps(request),encoding='utf-8')
diff --git a/requirements.txt b/requirements.txt
index 913a4d9..83ba5f3 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,8 +1,17 @@
-pyst==0.6.50
-SQLAlchemy==0.9.9
Flask==0.10.1
+Flask-Cors==2.1.2
+Flask-Login==0.3.0
Flask-Restless==0.17.0
Flask-SQLAlchemy==2.0
-flask-login==0.3.0
+itsdangerous==0.24
+Jinja2==2.8
+MarkupSafe==0.23
+mimerender==0.6.0
+pyst2==0.4.9
+python-dateutil==2.5.3
+python-mimeparse==1.5.2
pyzmq==15.0.0
requests==2.9.0
+six==1.10.0
+SQLAlchemy==0.9.9
+Werkzeug==0.11.10
diff --git a/templates/anonymous.html b/templates/anonymous.html
new file mode 100644
index 0000000..a4c1634
--- /dev/null
+++ b/templates/anonymous.html
@@ -0,0 +1,10 @@
+
+
+ login
+
+
+
+ Vem Vindo
+ clique aqui para fazer login
+
+
\ No newline at end of file
diff --git a/templates/index.html b/templates/index.html
index 855b797..835b528 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -7,7 +7,7 @@
Hi {{ current_user.username }}!
{% endif %}
- Vem Bindo
+ Vem Vindo