initial upload
This commit is contained in:
4
CHANGES.txt
Normal file
4
CHANGES.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
0.1
|
||||
---
|
||||
|
||||
- Initial version.
|
||||
2
MANIFEST.in
Normal file
2
MANIFEST.in
Normal file
@@ -0,0 +1,2 @@
|
||||
include *.txt *.ini *.cfg *.rst
|
||||
recursive-include cao_osint *.ico *.png *.css *.gif *.jpg *.pt *.txt *.mak *.mako *.js *.html *.xml *.jinja2
|
||||
29
README.md
Normal file
29
README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# README #
|
||||
|
||||
**cao_osint** est une application pour créer un blog simple. Elle est inspirée du tutorial [**pyramid_blogr**](https://docs.pylonsproject.org/projects/pyramid-blogr/en/latest/index.html).
|
||||
|
||||
## Fonctionnalités ##
|
||||
|
||||
Bien que **cao_osint** soit une application minimale et simple, elle possède toutes les fonctions nécessaire pour gérer un blog :
|
||||
|
||||
- Gestion des utilisateurs du blog (admin ou rédacteur)
|
||||
- Authentification et autorisation des utilisateurs
|
||||
- Gestion des posts du blog avec des statuts : *publié, brouillon ou privé*
|
||||
- Gestion des tags (un post peut avoir un tag)
|
||||
- Les posts sont rédigé avec le langage *Markdown*
|
||||
- Possibilité de faire des recherches sur le titre et le corps des posts
|
||||
|
||||
## Add-on requis ##
|
||||
|
||||
- Python 3.7.1
|
||||
- Pyramid 1.10
|
||||
- SQLite 3.35.5
|
||||
- pyramid-jinja2 2.7 : view templating
|
||||
- wtforms 2.2.1 : form library
|
||||
- webhelpers2 2.0 : various web building related helpers
|
||||
- Markdown 3.4.1 :
|
||||
|
||||
|
||||
### 1.0 (22.01.2023)
|
||||
|
||||
- version initiale
|
||||
BIN
cao_osint.sqlite
Normal file
BIN
cao_osint.sqlite
Normal file
Binary file not shown.
27
cao_osint/__init__.py
Normal file
27
cao_osint/__init__.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from pyramid.config import Configurator
|
||||
from pyramid.authentication import AuthTktAuthenticationPolicy
|
||||
from pyramid.authorization import ACLAuthorizationPolicy
|
||||
from pyramid.session import SignedCookieSessionFactory
|
||||
|
||||
from .services.user import groupfinder
|
||||
|
||||
|
||||
def main(global_config, **settings):
|
||||
""" This function returns a Pyramid WSGI application.
|
||||
"""
|
||||
# session factory
|
||||
my_session_factory = SignedCookieSessionFactory('dnAFXEqr5VpKtW')
|
||||
|
||||
authentication_policy = AuthTktAuthenticationPolicy('ssLZLBIN39jFWn',
|
||||
callback=groupfinder, hashalg='sha512', timeout=36000)
|
||||
authorization_policy = ACLAuthorizationPolicy()
|
||||
with Configurator(settings=settings,
|
||||
root_factory='cao_osint.security.RootFactory',
|
||||
authentication_policy=authentication_policy,
|
||||
authorization_policy=authorization_policy) as config:
|
||||
config.include('pyramid_jinja2')
|
||||
config.include('.models')
|
||||
config.include('.routes')
|
||||
config.set_session_factory(my_session_factory)
|
||||
config.scan()
|
||||
return config.make_wsgi_app()
|
||||
58
cao_osint/alembic/env.py
Normal file
58
cao_osint/alembic/env.py
Normal file
@@ -0,0 +1,58 @@
|
||||
"""Pyramid bootstrap environment. """
|
||||
from alembic import context
|
||||
from pyramid.paster import get_appsettings, setup_logging
|
||||
from sqlalchemy import engine_from_config
|
||||
|
||||
from cao_osint.models.meta import Base
|
||||
|
||||
config = context.config
|
||||
|
||||
setup_logging(config.config_file_name)
|
||||
|
||||
settings = get_appsettings(config.config_file_name)
|
||||
target_metadata = Base.metadata
|
||||
|
||||
|
||||
def run_migrations_offline():
|
||||
"""Run migrations in 'offline' mode.
|
||||
|
||||
This configures the context with just a URL
|
||||
and not an Engine, though an Engine is acceptable
|
||||
here as well. By skipping the Engine creation
|
||||
we don't even need a DBAPI to be available.
|
||||
|
||||
Calls to context.execute() here emit the given string to the
|
||||
script output.
|
||||
|
||||
"""
|
||||
context.configure(url=settings['sqlalchemy.url'])
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
|
||||
def run_migrations_online():
|
||||
"""Run migrations in 'online' mode.
|
||||
|
||||
In this scenario we need to create an Engine
|
||||
and associate a connection with the context.
|
||||
|
||||
"""
|
||||
engine = engine_from_config(settings, prefix='sqlalchemy.')
|
||||
|
||||
connection = engine.connect()
|
||||
context.configure(
|
||||
connection=connection,
|
||||
target_metadata=target_metadata
|
||||
)
|
||||
|
||||
try:
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
finally:
|
||||
connection.close()
|
||||
|
||||
|
||||
if context.is_offline_mode():
|
||||
run_migrations_offline()
|
||||
else:
|
||||
run_migrations_online()
|
||||
22
cao_osint/alembic/script.py.mako
Normal file
22
cao_osint/alembic/script.py.mako
Normal file
@@ -0,0 +1,22 @@
|
||||
"""${message}
|
||||
|
||||
Revision ID: ${up_revision}
|
||||
Revises: ${down_revision | comma,n}
|
||||
Create Date: ${create_date}
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
${imports if imports else ""}
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = ${repr(up_revision)}
|
||||
down_revision = ${repr(down_revision)}
|
||||
branch_labels = ${repr(branch_labels)}
|
||||
depends_on = ${repr(depends_on)}
|
||||
|
||||
def upgrade():
|
||||
${upgrades if upgrades else "pass"}
|
||||
|
||||
def downgrade():
|
||||
${downgrades if downgrades else "pass"}
|
||||
26
cao_osint/alembic/versions/20230121_a632e375e7dc.py
Normal file
26
cao_osint/alembic/versions/20230121_a632e375e7dc.py
Normal file
@@ -0,0 +1,26 @@
|
||||
"""init
|
||||
|
||||
Revision ID: a632e375e7dc
|
||||
Revises:
|
||||
Create Date: 2023-01-21 11:25:48.517435
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'a632e375e7dc'
|
||||
down_revision = None
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
def upgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_column('entries', 'author')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
def downgrade():
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('entries', sa.Column('author', sa.VARCHAR(length=50), nullable=True))
|
||||
# ### end Alembic commands ###
|
||||
1
cao_osint/alembic/versions/README.txt
Normal file
1
cao_osint/alembic/versions/README.txt
Normal file
@@ -0,0 +1 @@
|
||||
Placeholder for alembic versions
|
||||
36
cao_osint/forms.py
Normal file
36
cao_osint/forms.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from wtforms import Form, StringField, TextAreaField, SelectField, validators
|
||||
from wtforms import IntegerField, PasswordField
|
||||
from wtforms.validators import InputRequired, Length, EqualTo
|
||||
from wtforms.widgets import HiddenInput
|
||||
|
||||
strip_filter = lambda x: x.strip() if x else None
|
||||
|
||||
class BlogCreateForm(Form):
|
||||
title = StringField('Titre', validators=[InputRequired(), Length(min=1, max=255)],
|
||||
filters=[strip_filter])
|
||||
body = TextAreaField('Corps du texte', validators=[InputRequired(), Length(min=1)],
|
||||
filters=[strip_filter])
|
||||
tag = SelectField('Tag')
|
||||
status = SelectField('Statut', choices=[('brouillon','Brouillon'),('privé','Privé'),('publié','Publié')])
|
||||
|
||||
class BlogUpdateForm(BlogCreateForm):
|
||||
id = IntegerField(widget=HiddenInput())
|
||||
|
||||
class BlogSearchForm(Form):
|
||||
criteria = StringField('Recherche', validators=[InputRequired(), Length(min=3, max=45)],
|
||||
filters=[strip_filter])
|
||||
|
||||
class TagForm(Form):
|
||||
id = IntegerField(widget=HiddenInput())
|
||||
tag = StringField('Tag', validators=[InputRequired(), Length(min=1, max=25)],
|
||||
filters=[strip_filter])
|
||||
|
||||
|
||||
class UserCreateForm(Form):
|
||||
id = IntegerField(widget=HiddenInput())
|
||||
name = StringField('Nom', validators=[InputRequired(), Length(min=1, max=255)],
|
||||
filters=[strip_filter])
|
||||
password = PasswordField('Mot de passe')
|
||||
|
||||
confirm = PasswordField('Confirmer', validators=[EqualTo('password', message='Les 2 mots de passe doivent être identiques')])
|
||||
|
||||
78
cao_osint/models/__init__.py
Normal file
78
cao_osint/models/__init__.py
Normal file
@@ -0,0 +1,78 @@
|
||||
from sqlalchemy import engine_from_config
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy.orm import configure_mappers
|
||||
import zope.sqlalchemy
|
||||
|
||||
# import or define all models here to ensure they are attached to the
|
||||
# Base.metadata prior to any initialization routines
|
||||
from .user import User
|
||||
from .blog_record import BlogRecord
|
||||
|
||||
# run configure_mappers after defining all of the models to ensure
|
||||
# all relationships can be setup
|
||||
configure_mappers()
|
||||
|
||||
|
||||
def get_engine(settings, prefix='sqlalchemy.'):
|
||||
return engine_from_config(settings, prefix)
|
||||
|
||||
|
||||
def get_session_factory(engine):
|
||||
factory = sessionmaker()
|
||||
factory.configure(bind=engine)
|
||||
return factory
|
||||
|
||||
|
||||
def get_tm_session(session_factory, transaction_manager):
|
||||
"""
|
||||
Get a ``sqlalchemy.orm.Session`` instance backed by a transaction.
|
||||
|
||||
This function will hook the session to the transaction manager which
|
||||
will take care of committing any changes.
|
||||
|
||||
- When using pyramid_tm it will automatically be committed or aborted
|
||||
depending on whether an exception is raised.
|
||||
|
||||
- When using scripts you should wrap the session in a manager yourself.
|
||||
For example::
|
||||
|
||||
import transaction
|
||||
|
||||
engine = get_engine(settings)
|
||||
session_factory = get_session_factory(engine)
|
||||
with transaction.manager:
|
||||
dbsession = get_tm_session(session_factory, transaction.manager)
|
||||
|
||||
"""
|
||||
dbsession = session_factory()
|
||||
zope.sqlalchemy.register(
|
||||
dbsession, transaction_manager=transaction_manager)
|
||||
return dbsession
|
||||
|
||||
|
||||
def includeme(config):
|
||||
"""
|
||||
Initialize the model for a Pyramid app.
|
||||
|
||||
Activate this setup using ``config.include('cao_osint.models')``.
|
||||
|
||||
"""
|
||||
settings = config.get_settings()
|
||||
settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
|
||||
|
||||
# use pyramid_tm to hook the transaction lifecycle to the request
|
||||
config.include('pyramid_tm')
|
||||
|
||||
# use pyramid_retry to retry a request when transient exceptions occur
|
||||
config.include('pyramid_retry')
|
||||
|
||||
session_factory = get_session_factory(get_engine(settings))
|
||||
config.registry['dbsession_factory'] = session_factory
|
||||
|
||||
# make request.dbsession available for use in Pyramid
|
||||
config.add_request_method(
|
||||
# r.tm is the transaction manager used by pyramid_tm
|
||||
lambda r: get_tm_session(session_factory, r.tm),
|
||||
'dbsession',
|
||||
reify=True
|
||||
)
|
||||
40
cao_osint/models/blog_record.py
Normal file
40
cao_osint/models/blog_record.py
Normal file
@@ -0,0 +1,40 @@
|
||||
import datetime #<- will be used to set default dates on models
|
||||
from cao_osint.models.meta import Base #<- we need to import our sqlalchemy metadata from which model classes will inherit
|
||||
from sqlalchemy import (
|
||||
Column,
|
||||
Integer,
|
||||
Unicode, #<- will provide Unicode field
|
||||
UnicodeText, #<- will provide Unicode text field
|
||||
DateTime, #<- time abstraction field
|
||||
)
|
||||
from webhelpers2.text import urlify #<- will generate slugs
|
||||
from webhelpers2.date import distance_of_time_in_words #<- human friendly dates
|
||||
|
||||
|
||||
class BlogRecord(Base):
|
||||
__tablename__ = 'entries'
|
||||
id = Column(Integer, primary_key=True)
|
||||
title = Column(Unicode(255), unique=True, nullable=False)
|
||||
body = Column(UnicodeText, default='')
|
||||
created = Column(DateTime, default=datetime.datetime.now)
|
||||
creator = Column(Unicode(50), default='')
|
||||
edited = Column(DateTime, default=datetime.datetime.now)
|
||||
editor = Column(Unicode(50), default='')
|
||||
tag = Column(Unicode(25))
|
||||
status = Column(Unicode(50), default='brouillon')
|
||||
|
||||
@property
|
||||
def slug(self):
|
||||
return urlify(self.title)
|
||||
|
||||
@property
|
||||
def created_in_words(self):
|
||||
return distance_of_time_in_words(self.created,
|
||||
datetime.datetime.utcnow())
|
||||
|
||||
|
||||
class Tags(Base):
|
||||
__tablename__ = 'tags'
|
||||
id = Column(Integer, primary_key=True)
|
||||
tag = Column(Unicode(25))
|
||||
|
||||
16
cao_osint/models/meta.py
Normal file
16
cao_osint/models/meta.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.schema import MetaData
|
||||
|
||||
# Recommended naming convention used by Alembic, as various different database
|
||||
# providers will autogenerate vastly different names making migrations more
|
||||
# difficult. See: http://alembic.zzzcomputing.com/en/latest/naming.html
|
||||
NAMING_CONVENTION = {
|
||||
"ix": "ix_%(column_0_label)s",
|
||||
"uq": "uq_%(table_name)s_%(column_0_name)s",
|
||||
"ck": "ck_%(table_name)s_%(constraint_name)s",
|
||||
"fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
|
||||
"pk": "pk_%(table_name)s"
|
||||
}
|
||||
|
||||
metadata = MetaData(naming_convention=NAMING_CONVENTION)
|
||||
Base = declarative_base(metadata=metadata)
|
||||
34
cao_osint/models/user.py
Normal file
34
cao_osint/models/user.py
Normal file
@@ -0,0 +1,34 @@
|
||||
import datetime #<- will be used to set default dates on models
|
||||
from cao_osint.models.meta import Base #<- we need to import our sqlalchemy metadata from which model classes will inherit
|
||||
from sqlalchemy import (
|
||||
Column,
|
||||
Integer,
|
||||
Unicode, #<- will provide Unicode field
|
||||
UnicodeText, #<- will provide Unicode text field
|
||||
DateTime, #<- time abstraction field
|
||||
)
|
||||
|
||||
from passlib.apps import custom_app_context as blogger_pwd_context
|
||||
|
||||
|
||||
class User(Base):
|
||||
__tablename__ = 'users'
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(Unicode(255), unique=True, nullable=False)
|
||||
password = Column(Unicode(255), nullable=False)
|
||||
last_logged = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
|
||||
def verify_password(self, password):
|
||||
# is it cleartext?
|
||||
if password == self.password:
|
||||
self.set_password(password)
|
||||
# verify password
|
||||
result = blogger_pwd_context.verify(password, self.password)
|
||||
if result:
|
||||
# pwd OK, set last login date
|
||||
self.last_logged = datetime.datetime.now()
|
||||
return result
|
||||
|
||||
def set_password(self, password):
|
||||
password_hash = blogger_pwd_context.encrypt(password)
|
||||
self.password = password_hash
|
||||
13
cao_osint/pshell.py
Normal file
13
cao_osint/pshell.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from . import models
|
||||
|
||||
|
||||
def setup(env):
|
||||
request = env['request']
|
||||
|
||||
# start a transaction
|
||||
request.tm.begin()
|
||||
|
||||
# inject some vars into the shell builtins
|
||||
env['tm'] = request.tm
|
||||
env['dbsession'] = request.dbsession
|
||||
env['models'] = models
|
||||
15
cao_osint/routes.py
Normal file
15
cao_osint/routes.py
Normal file
@@ -0,0 +1,15 @@
|
||||
def includeme(config):
|
||||
config.add_static_view('static', 'static', cache_max_age=3600)
|
||||
config.add_route('home', '/')
|
||||
config.add_route('apropos', '/apropos')
|
||||
config.add_route('blog', '/blog/{id:\d+}/{slug}')
|
||||
config.add_route('blog_edit', '/blog_edit/{id}')
|
||||
config.add_route('blog_search', '/blog_search')
|
||||
config.add_route('login', '/login')
|
||||
config.add_route('logout', '/logout')
|
||||
config.add_route('tags', '/tags')
|
||||
config.add_route('tag_edit', '/tag_edit/{id}')
|
||||
config.add_route('uploads', '/uploads')
|
||||
config.add_route('upload_edit', '/upload_edit/{filename}')
|
||||
config.add_route('users', '/users')
|
||||
config.add_route('user_edit', '/user_edit/{name}')
|
||||
1
cao_osint/scripts/__init__.py
Normal file
1
cao_osint/scripts/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# package
|
||||
49
cao_osint/scripts/initialize_db.py
Normal file
49
cao_osint/scripts/initialize_db.py
Normal file
@@ -0,0 +1,49 @@
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
from pyramid.paster import bootstrap, setup_logging
|
||||
from sqlalchemy.exc import OperationalError
|
||||
|
||||
from .. import models
|
||||
|
||||
|
||||
def setup_models(dbsession):
|
||||
"""
|
||||
Add or update models / fixtures in the database.
|
||||
|
||||
"""
|
||||
|
||||
model = models.user.User(name=u'admin', password=u'pcao.7513')
|
||||
dbsession.add(model)
|
||||
|
||||
|
||||
def parse_args(argv):
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'config_uri',
|
||||
help='Configuration file, e.g., development.ini',
|
||||
)
|
||||
return parser.parse_args(argv[1:])
|
||||
|
||||
|
||||
def main(argv=sys.argv):
|
||||
args = parse_args(argv)
|
||||
setup_logging(args.config_uri)
|
||||
env = bootstrap(args.config_uri)
|
||||
|
||||
try:
|
||||
with env['request'].tm:
|
||||
dbsession = env['request'].dbsession
|
||||
setup_models(dbsession)
|
||||
except OperationalError:
|
||||
print('''
|
||||
Pyramid is having a problem using your SQL database. The problem
|
||||
might be caused by one of the following things:
|
||||
|
||||
1. You may need to initialize your database tables with `alembic`.
|
||||
Check your README.txt for description and try to run it.
|
||||
|
||||
2. Your database server may not be running. Check that the
|
||||
database server referred to by the "sqlalchemy.url" setting in
|
||||
your "development.ini" file is running.
|
||||
''')
|
||||
15
cao_osint/security.py
Normal file
15
cao_osint/security.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from pyramid.security import (
|
||||
Allow,
|
||||
Authenticated,
|
||||
DENY_ALL,
|
||||
)
|
||||
|
||||
class RootFactory(object):
|
||||
"""Defines an ACL for groups/permissions mapping"""
|
||||
__acl__ = [ (Allow, Authenticated, 'view'),
|
||||
(Allow, 'group:administrators', 'manage'),
|
||||
DENY_ALL,
|
||||
]
|
||||
def __init__(self, request):
|
||||
pass
|
||||
|
||||
0
cao_osint/services/__init__.py
Normal file
0
cao_osint/services/__init__.py
Normal file
57
cao_osint/services/blog_record.py
Normal file
57
cao_osint/services/blog_record.py
Normal file
@@ -0,0 +1,57 @@
|
||||
import sqlalchemy as sa
|
||||
import datetime #<- will be used to set default dates on models
|
||||
|
||||
from sqlalchemy import or_
|
||||
from ..models.blog_record import BlogRecord, Tags
|
||||
|
||||
|
||||
|
||||
class BlogRecordService(object):
|
||||
|
||||
@classmethod
|
||||
def by_criteria(cls, request, criteria):
|
||||
search = "%{}%".format(criteria)
|
||||
query = request.dbsession.query(BlogRecord)
|
||||
if request.authenticated_userid == None:
|
||||
# if user is anonym, display only published posts
|
||||
query = query.filter(BlogRecord.status == 'publié')
|
||||
query = query.filter(or_(BlogRecord.title.like(search),
|
||||
BlogRecord.body.like(search))).all()
|
||||
return query
|
||||
|
||||
@classmethod
|
||||
def by_id(cls, request, _id):
|
||||
query = request.dbsession.query(BlogRecord)
|
||||
return query.get(_id)
|
||||
|
||||
@classmethod
|
||||
def get_last_created(cls, request):
|
||||
# gest the 10 last created posts
|
||||
query = request.dbsession.query(BlogRecord)
|
||||
if request.authenticated_userid == None:
|
||||
# if user is anonym, display only published posts
|
||||
query = query.filter(BlogRecord.status == 'publié')
|
||||
query = query.order_by(sa.desc(BlogRecord.created)).limit(10).all()
|
||||
return query
|
||||
|
||||
@classmethod
|
||||
def delete(cls, request, id):
|
||||
request.dbsession.query(BlogRecord).filter(BlogRecord.id == id).delete(synchronize_session=False)
|
||||
return
|
||||
|
||||
@classmethod
|
||||
def get_tags(cls, request):
|
||||
query = request.dbsession.query(Tags)
|
||||
query = query.order_by(Tags.tag).all()
|
||||
return query
|
||||
|
||||
@classmethod
|
||||
def get_tags_byId(cls, request, id):
|
||||
# gest the last 5 items modified
|
||||
query = request.dbsession.query(Tags).filter(Tags.id == id).first()
|
||||
return query
|
||||
|
||||
@classmethod
|
||||
def tag_delete(cls, request, id):
|
||||
request.dbsession.query(Tags).filter(Tags.id == id).delete(synchronize_session=False)
|
||||
return
|
||||
32
cao_osint/services/user.py
Normal file
32
cao_osint/services/user.py
Normal file
@@ -0,0 +1,32 @@
|
||||
import sqlalchemy as sa
|
||||
from ..models.user import User
|
||||
|
||||
|
||||
class UserService(object):
|
||||
|
||||
@classmethod
|
||||
def all(cls, request):
|
||||
items = request.dbsession.query(User).order_by(sa.asc(User.name)).all()
|
||||
return items
|
||||
|
||||
@classmethod
|
||||
def by_name(cls, request, name ):
|
||||
item = request.dbsession.query(User).filter(User.name == name).first()
|
||||
return item
|
||||
|
||||
@classmethod
|
||||
def delete(cls, request, id):
|
||||
request.dbsession.query(User).filter(User.id == id).delete(synchronize_session=False)
|
||||
return
|
||||
|
||||
def groupfinder(userid, request):
|
||||
|
||||
if userid:
|
||||
# user name is 'admin' ?
|
||||
if userid == 'admin':
|
||||
return ['group:administrators']
|
||||
else:
|
||||
return [] # it means that userid is logged in
|
||||
else:
|
||||
# it returns None if userid isn't logged in
|
||||
return None
|
||||
BIN
cao_osint/static/favicon.ico
Normal file
BIN
cao_osint/static/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
cao_osint/static/pyramid-16x16.png
Normal file
BIN
cao_osint/static/pyramid-16x16.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
BIN
cao_osint/static/pyramid.png
Normal file
BIN
cao_osint/static/pyramid.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
143
cao_osint/static/theme.css
Normal file
143
cao_osint/static/theme.css
Normal file
@@ -0,0 +1,143 @@
|
||||
/* Theme inspired from Bootstrap Theme "The Band" */
|
||||
/* https://www.w3schools.com/bootstrap/bootstrap_theme_band.asp */
|
||||
|
||||
body {
|
||||
font: 400 19px/1.8 Georgia, serif;
|
||||
color: #777;
|
||||
}
|
||||
h3, h4 {
|
||||
margin: 10px 0 30px 0;
|
||||
letter-spacing: 10px;
|
||||
font-size: 20px;
|
||||
color: #111;
|
||||
}
|
||||
.container {
|
||||
padding: 80px 120px;
|
||||
}
|
||||
.person {
|
||||
border: 10px solid transparent;
|
||||
margin-bottom: 25px;
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
opacity: 0.7;
|
||||
}
|
||||
.person:hover {
|
||||
border-color: #f1f1f1;
|
||||
}
|
||||
.carousel-inner img {
|
||||
-webkit-filter: grayscale(90%);
|
||||
filter: grayscale(90%); /* make all photos black and white */
|
||||
width: 100%; /* Set width to 100% */
|
||||
margin: auto;
|
||||
}
|
||||
.carousel-caption h3 {
|
||||
color: #fff !important;
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
.carousel-caption {
|
||||
display: none; /* Hide the carousel text when the screen is less than 600 pixels wide */
|
||||
}
|
||||
}
|
||||
.bg-1 {
|
||||
background: #bc2131;
|
||||
color: #bdbdbd;
|
||||
}
|
||||
.bg-1 h3 {color: #fff;}
|
||||
.bg-1 p {font-style: italic;}
|
||||
.list-group-item:first-child {
|
||||
border-top-right-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
}
|
||||
.list-group-item:last-child {
|
||||
border-bottom-right-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
.thumbnail {
|
||||
padding: 0 0 15px 0;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
.thumbnail p {
|
||||
margin-top: 15px;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.modal-header, h4, .close {
|
||||
background-color: #333;
|
||||
color: #fff !important;
|
||||
text-align: center;
|
||||
font-size: 30px;
|
||||
}
|
||||
.modal-header, .modal-body {
|
||||
padding: 40px 50px;
|
||||
}
|
||||
.nav-tabs li a {
|
||||
color: #777;
|
||||
}
|
||||
#googleMap {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
-webkit-filter: grayscale(100%);
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
.navbar {
|
||||
font-family: Montserrat, sans-serif;
|
||||
margin-bottom: 0;
|
||||
background-color: #bc2131;
|
||||
border: 0;
|
||||
font-size: 14px !important;
|
||||
letter-spacing: 4px;
|
||||
opacity: 0.9;
|
||||
}
|
||||
.navbar li a, .navbar .navbar-brand {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
.navbar-nav li a:hover {
|
||||
color: #fff !important;
|
||||
}
|
||||
.navbar-nav li.active a {
|
||||
color: #fff !important;
|
||||
background-color: #29292c !important;
|
||||
}
|
||||
.navbar-default .navbar-toggle {
|
||||
border-color: transparent;
|
||||
}
|
||||
footer {
|
||||
background-color: #bc2131;
|
||||
color: #f5f5f5;
|
||||
padding: 32px;
|
||||
}
|
||||
footer a {
|
||||
color: #f5f5f5;
|
||||
}
|
||||
footer a:hover {
|
||||
color: #777;
|
||||
text-decoration: none;
|
||||
}
|
||||
.form-control {
|
||||
border-radius: 0;
|
||||
}
|
||||
textarea {
|
||||
resize: none;
|
||||
}
|
||||
.required-field::after {
|
||||
content: "*";
|
||||
color: red;
|
||||
margin-left:2px;
|
||||
}
|
||||
|
||||
/* Dropdown */
|
||||
.open .dropdown-toggle {
|
||||
color: #fff ;
|
||||
background-color: #555 !important;
|
||||
}
|
||||
|
||||
/* Dropdown links */
|
||||
.dropdown-menu li a {
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
/* On hover, the dropdown links will turn red */
|
||||
.dropdown-menu li a:hover {
|
||||
background-color: red !important;
|
||||
}
|
||||
253
cao_osint/static/uploads/articles.csv
Normal file
253
cao_osint/static/uploads/articles.csv
Normal file
@@ -0,0 +1,253 @@
|
||||
REF;LIBART;libelle;PRIXHT1;PRIXHT2;PRIXHT3;PRIXHT4;PRIXHT5;PRIXHT6;PRIXHT7;PRIXHT8;PRIXHT9;PRIXHT10;ref_cli1;ref_cli2;ref_cli3;ref_cli4;ref_cli5;ref_cli6;ref_cli7;ref_cli8;ref_cli9;ref_cli10;UNITE;FAM;LIBCOMPL1;LIBCOMPL2;LIBCOMPL3;LIBCOMPL4;cree_le;modif_le
|
||||
1;"1 face";NULL;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;;;;;;;;;;;T;------;;;;"2021-11-16 15:27:20";"2022-01-19 14:40:58"
|
||||
2;"2 faces";"2 faces -------";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;-------;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
3;"3 faces";"3 faces -------";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;-------;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
4;"4 faces";"4 faces -------";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;-------;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
AAP;"Arêtes et angles plaqués";"Arêtes et angles plaqués";15.24;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;ML;PLA;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
AC;ACCUEIL;"ACCUEIL =======";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;=======;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
AL;ALCOVE;"ALCOVE ======";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;======;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
AME;"Aménagement, mise en place et";"Aménagement, mise en place et repli y compris déplacements pour suivi :";250.00;0.00;250.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;;;;;;;;;;;ASS;"repli y compris déplacements pour suivi :";;;;"2020-01-15 15:55:21";"2021-10-27 09:10:00"
|
||||
API;"Arrachage, préparations et pose de";"Arrachage, préparations et pose de papier ingrain :";21.50;16.27;18.80;18.00;22.00;16.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PNT;"papier ingrain :";;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
APR;"Pose de revêtement mural sur préparations :";"Pose de revêtement mural sur préparations :";25.00;23.07;18.80;22.50;25.00;25.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PNT;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
ASS;"Pose d'un déshumidificateur :";"Pose d'un assécheur :";30.00;0.00;30.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;;;;;;;;;;;ASS;;;;;"2020-01-15 15:50:50";"2021-10-27 09:08:49"
|
||||
ASS26;"Assèchement ambiant habitation y ";NULL;0.00;343.20;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;ASS_26_ASSEC;;;;;;;;;;ASS;"compris amenée, repli et location";"du matériel d'un appareil limité à";"3 semaines :";;"2022-05-12 09:12:07";"2022-06-30 09:03:17"
|
||||
ASS27;"Assèchement ambiant habitation par ";NULL;0.00;171.60;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;ASS_27_ASSEC;;;;;;;;;;ASS;"appareil supplémentaire limité à";"3 semaines :";;;"2022-06-30 09:03:48";"2022-06-30 09:12:52"
|
||||
B;Boiseries;"Boiseries ---------";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;---------;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
BAL;BALCON;"BALCON ======";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;======;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
BU;BUREAU;"BUREAU ======";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;======;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
BUA;BUANDERIE;"BUANDERIE =========";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;=========;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
C;"Coupes et arasements :";"Coupes et arasements :";1.50;1.50;1.50;1.50;1.50;1.50;1.50;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;0;PNT;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
CA;"Mise en peinture de canalisations ou";"Mise en peinture de canalisations ou tuyauteries :";0.00;5.75;3.10;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_9_PEINTU;;;;;;;;;;PEI;"tuyauteries :";;;;"2019-06-12 12:08:15";"2019-06-12 12:09:05"
|
||||
CAF005;"Démolition de faïence et reprise";NULL;0.00;0.00;0.00;0.00;0.00;0.00;15.29;0.00;0.00;0.00;;;;;;;CAF005;;;;;CAR;"d'enduit :";;;;"2021-11-30 17:21:29";"2021-11-30 17:22:22"
|
||||
CAF010;"Fourniture et pose de faïence";NULL;0.00;0.00;0.00;0.00;0.00;0.00;46.72;0.00;0.00;0.00;;;;;;;CAF010;;;;;CAR;"blanche 25 * 33 non compris";"dépose :";;;"2021-11-30 17:25:37";"2021-11-30 17:27:03"
|
||||
CAF036;"Fourniture et pose d'un tablier de";NULL;0.00;0.00;0.00;0.00;0.00;0.00;123.31;0.00;0.00;0.00;;;;;;;CAF036;;;;;CAR;"baignoire avec habillage faïence";"et trappe de visite :";;;"2021-11-30 17:28:34";"2022-03-30 15:34:50"
|
||||
CAF043;"Fourniture et pose de faïence";NULL;0.00;0.00;0.00;0.00;0.00;0.00;50.95;0.00;0.00;0.00;;;;;;;CAF043;;;;;CAR;"Forfait sur lavabo :";;;;"2021-11-30 17:27:21";"2021-11-30 17:28:19"
|
||||
CAF052;"Fourniture et pose de faïence";NULL;0.00;0.00;0.00;0.00;0.00;0.00;53.32;0.00;0.00;0.00;;;;;;;CAF052;;;;;CAR;"métro :";;;;"2021-11-30 17:22:51";"2022-03-30 15:35:01"
|
||||
CAR0;"Prestations hors référentiel";"Prestations hors référentiel tarifaire :";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;CAR_0_HORBPU;;;;;;;;;;CAR;"tarifaire :";;;;"2019-08-07 08:57:16";"2022-01-18 08:53:56"
|
||||
CAR10;"Fourniture et pose d'un tablier de";"Fourniture et pose d'un tablier de baignoire hors carrelage :";0.00;293.70;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;CAR_10_TABLI;;;;;;;;;;CAR;"baignoire hors carrelage :";;;;"2019-08-07 09:03:35";"2022-07-04 09:53:34"
|
||||
CAR14;"Facturation minimale d'intervention";"Facturation minimale d'intervention carrelage :";0.00;330.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;CAR_14_FACTU;;;;;;;;;;CAR;"carrelage :";;;;"2019-08-07 08:58:24";"2019-08-07 08:59:31"
|
||||
CAR15;"Remplacement de sous couche acoustique";NULL;0.00;45.20;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;CAR_15_REMPL;;;;;;;;;;CAR;"ou étanchéité sous carrelage y compris ";"arrachage, préparation des supports,";"revêtement ";;"2022-10-10 16:39:33";"2022-10-10 16:41:38"
|
||||
CAR3;"Démolition, évacuation et pose de";"Démolition, évacuation et pose de carrelage au sol collé ou scellé y compris préparations :";0.00;79.10;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;CAR_3_DEMOL;;;;;;;;;;CAR;"carrelage au sol collé ou scellé y ";"compris préparations :";;;"2019-08-07 08:40:36";"2022-07-04 09:54:12"
|
||||
CAR4;"Démolition, évacuation et pose de";"Démolition, évacuation et pose de carrelage aux murs, collé ou scellé y compris préparations :";0.00;73.50;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;CAR_4_DEMOL;;;;;;;;;;CAR;"carrelage aux murs, collé ou scellé";"y compris préparations : ";;;"2019-08-07 08:46:15";"2022-07-04 09:56:34"
|
||||
CAR5;"Fourniture de carrelage ou faience :";"Fourniture de carrelage ou faience :";0.00;23.60;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;CAR_5_FOURN;;;;;;;;;;CAR;;;;;"2019-08-07 08:48:47";"2022-07-04 09:56:44"
|
||||
CAR6;"Démolition, évacuation et pose de";"Démolition, évacuation et pose de plinthes collées ou scellées y compris préparations :";0.00;12.60;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;CAR_6_DEMOL;;;;;;;;;;CAR;"plinthes collées ou scellées y compris";"préparations :";;;"2019-08-07 08:49:50";"2022-07-04 09:56:59"
|
||||
CAR7;"Fourniture de plinthes carrelage :";"Fourniture de plinthes carrelage :";0.00;20.10;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;CAR_7_FOURN;;;;;;;;;;CAR;;;;;"2019-08-07 08:51:00";"2022-07-04 09:57:14"
|
||||
CE;CELLIER;"CELLIER =======";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;=======;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
CH;CHAMBRE;"CHAMBRE =======";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;=======;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
CH1;"CHAMBRE 1";"CHAMBRE 1 =========";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;=========;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
CH2;"CHAMBRE 2";"CHAMBRE 2 =========";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;=========;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
CH3;"CHAMBRE 3";"CHAMBRE 3 =========";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;=========;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
CH4;"CHAMBRE 4";"CHAMBRE 4 =========";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;=========;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
CH5;"CHAMBRE 5";"CHAMBRE 5 =========";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;=========;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
CHA16;"Remplacement laine de verre en";"Remplacement laine de verre en kraft par 80 mm pour isolation des combles :";0.00;15.70;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;CHA_16_LAINE;;;;;;;;;;MEN;"kraft par 80 mm pour isolation";"des combles :";;;"2020-06-22 10:27:13";"2022-07-04 09:57:45"
|
||||
CHE;"CHAMBRE ENFANT";"CHAMBRE ENFANT ==============";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;==============;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
CHF;"CHAMBRE FILLE";"CHAMBRE FILLE =============";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;=============;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
CHG;"CHAMBRE GARCON";"CHAMBRE GARCON ==============";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;==============;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
CHP;"CHAMBRE PARENTS";"CHAMBRE PARENTS ===============";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;===============;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
CM;"Cristallisation de marbre :";"Cristallisation de marbre :";53.00;53.00;53.00;53.00;53.00;53.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;SOL;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
CO;COULOIR;"COULOIR =======";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;=======;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
COVID;"Forfait protocole sanitaire COVID";"Forfait protocole sanitaire COVID";27.28;27.28;27.28;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;;;;;;;;;;;T;;;;;"2020-05-07 08:42:11";"2021-01-04 10:07:39"
|
||||
CR;"COIN REPAS";"COIN REPAS ==========";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;==========;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
CU;CUISINE;"CUISINE =======";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;=======;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
D;"Dépose de moquette collée ou revêtement";"Dépose de moquette collée ou revêtement PVC collé :";8.00;0.00;7.22;7.25;0.00;8.40;5.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;SOL;"PVC collé :";;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
DAL;"Arrachage des dalles existantes, préparations";"Arrachage des dalles existantes, préparations des fonds et pose de dalles collées :";28.50;18.55;28.50;20.70;22.80;19.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;SOL;"des fonds et pose de dalles collées :";;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
DBA;"Dépose du faux plafond existant :";"Dépose du faux plafond existant :";23.00;23.00;29.50;22.77;23.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PLA;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
DE;DEBARRAS;"DEBARRAS ========";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;========;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
DEC3;"Décontamination, nettoyage des ";NULL;0.00;4.80;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;DEC_3_DECON;;;;;;;;;;ASS;"embellissement Plafond et Murs,";"lessivage :";;;"2020-12-11 17:12:10";"2022-07-04 09:58:28"
|
||||
DEG;DEGAGEMENT;"DEGAGEMENT ==========";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;==========;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
DMP;"Doublage des murs en placo :";"Doublage des murs en placo :";48.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PLA;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
DO;DOUCHE;"DOUCHE ======";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;======;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
DP;"Déplacement :";"Déplacement :";0.00;49.51;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PNT;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
DPP;"Dépose du revêtement de sol existant,";"Dépose du revêtement de sol existant, préparations des fonds et pose de revêtement collé :";25.50;21.16;21.30;25.88;21.00;16.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;SOL;"préparations des fonds et pose de revêtement";"collé :";;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
DR;DRESSING;"DRESSING ========";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;========;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
E;"Effeuillage, reprise d'enduit :";"Effeuillage, reprise d'enduit :";0.00;21.20;12.00;9.00;9.78;11.00;10.00;0.00;0.00;0.00;;PEN_22_REBOU;;;;;;;;;;PNT;;;;;"2017-08-15 09:18:37";"2022-07-08 15:55:04"
|
||||
EN;ENTREE;"ENTREE ======";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;======;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
EPD;"Enduit plâtre sur dégrossissage :";"Enduit plâtre sur dégrossissage :";52.00;19.50;22.28;0.00;0.00;38.00;0.00;0.00;0.00;0.00;;PEN_22_REBOU;;;;;;;;;;PLA;;;;;"2017-08-15 09:18:37";"2019-06-06 10:26:25"
|
||||
ER;"Effeuillage, remaillage :";"Effeuillage, remaillage :";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;0;PNT;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
F;"Fourniture :";"Fourniture :";35.00;35.00;35.00;35.00;35.00;35.00;35.00;0.00;0.00;0.00;;PEN_8_FOURNI;;;;;;;;;;PNT;;;;;"2017-08-15 09:18:37";"2021-09-30 10:01:28"
|
||||
FBS;"Fourniture et pose de barre de seuil :";"Fourniture et pose de barre de seuil :";25.30;17.00;25.30;14.28;17.50;17.00;0.00;0.00;0.00;0.00;;;;;;;;;;;;SOL;;;;;"2017-08-15 09:18:37";"2022-02-07 09:22:17"
|
||||
FMI;"Forfait minimun d'intervention :";"Forfait minimun d'intervention :";400.00;310.00;400.00;324.00;250.00;310.00;300.00;0.00;0.00;0.00;;PEN_21_FACTU;;;;;;;;;;PNT;;;;;"2017-08-15 09:18:37";"2022-02-10 09:24:30"
|
||||
FMP;"Forfait minimun d'intervention pour";"Forfait minimun d'intervention pour travaux de plâtrerie :";240.00;240.00;150.00;240.00;240.00;240.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PLA;"travaux de plâtrerie :";;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
FMS;"Forfait minimun shampoinage :";"Forfait minimun shampoinage :";150.00;150.00;150.00;150.00;150.00;150.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;SOL;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
FS;"Fourniture en m² :";"Fourniture en m² :";28.00;28.00;28.00;28.00;28.00;28.00;28.00;0.00;0.00;0.00;;PEN_16_FOUR;;;;;;;;;;PP;;;;;"2020-01-21 16:23:16";"2020-01-21 16:25:46"
|
||||
G;GARAGE;"GARAGE ======";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;======;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
GEN0;"Traitement responsable des";NULL;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;GEN_0_DECHET;;;;;;;;;;T;"déchets selon règlementation :";;;;"2022-02-07 11:54:58";"2022-02-07 11:56:04"
|
||||
GO;"Application de peinture projetée type";"Application de peinture projetée type gouttelettes sur murs ou plafond";0.00;28.80;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_4_APPLIC;;;;;;;;;;PEI;"gouttelettes sur murs ou plafond";;;;"2019-06-12 12:02:21";"2019-06-12 12:03:19"
|
||||
H;"HALL D'ENTREE";"HALL D'ENTREE =============";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;=============;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
HB;"Prestations hors référentiel";"Prestations hors référentiel tarifaire :";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_0_HORBPU;;;;;;;;;;T;"tarifaire :";;;;"2019-06-12 12:11:36";"2021-01-19 08:53:27"
|
||||
I;"Application d'une couche d'impression :";"Application d'une couche d'impression :";12.00;12.00;12.00;12.00;12.00;12.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PEI;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
IF;"Isolation des fumées par application";"Isolation des fumées par application d'un vernis :";12.96;12.96;12.96;12.96;12.96;12.96;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PEI;"d'un vernis :";;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
IPN;"Impression du plâtre ou du placoplâtre";"Impression du plâtre ou du placoplâtre neuf :";10.00;10.00;10.00;10.00;10.00;10.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PEI;"neuf :";;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
L;"Lessivage :";"Lessivage :";8.00;8.00;8.00;8.05;8.00;8.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;0;PEI;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
LC;"Lessivage à conserver :";"Lessivage à conserver :";10.00;5.98;6.10;8.05;5.50;8.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;0;PEI;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
M;Murs;"Murs ----";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;----;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
MAC0;"Prestation hors référentiel";NULL;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MAC_0_HORBPU;;;;;;;;;;MEN;"tarifaire :";;;;"2022-01-18 08:50:42";"2022-01-18 08:54:14"
|
||||
MAC10;"Briques pleines ordinaires avec joint";NULL;0.00;113.20;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MAC_10_BRIQ;;;;;;;;;;PLA;"1 cm, paroi de 10,5 cm ép :";;;;"2022-09-30 08:14:54";"2022-09-30 08:18:01"
|
||||
MAC11;"Briques creuses dite plâtrirère";NULL;0.00;30.80;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MAC_11_BRIQU;;;;;;;;;;PLA;"en pose traditionnelle, ép 5 cm :";;;;"2022-09-30 14:01:19";"2022-09-30 14:02:23"
|
||||
MAC3;"Démolition maçonnerie toutes";NULL;0.00;320.30;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MAC_03_DEMOL;;;;;;;;;;PLA;"natures de matériaux y compris";"fondations :";;;"2022-09-30 13:59:58";"2022-09-30 14:01:13"
|
||||
MB;"Murs et boiseries";"Murs et boiseries -----------------";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;-----------------;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
ME;"MONTEE D'ESCALIERS";"MONTEE D'ESCALIERS ==================";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;==================;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
MEN0;"Prestations hors référentiel";"Prestations hors référentiel tarifaire :";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_0_HORBPU;;;;;;;;;;MEN;"tarifaire :";;;;"2019-06-19 14:16:37";"2020-03-12 17:10:05"
|
||||
MEN10;"Remplacement de fenêtre, 1 à 2 vantaux";"Remplacement de fenêtre, 1 à 2 vantaux sur cadre existant, y compris dépose, réglages, ajustages, hors fourniture :";0.00;164.50;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_10_REMPL;;;;;;;;;;MEN;"sur cadre existant, y compris dépose,";"réglages, ajustages, hors fourniture :";;;"2019-11-27 15:17:15";"2022-07-04 10:02:26"
|
||||
MEN12;"Plus value par vantail suppl.";NULL;0.00;52.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_12_PLUSV;;;;;;;;;;MEN;"pour pose sur cadre existant ou";"scellée porte, porte-fenêtre et";"fenêtre :";;"2020-12-07 14:59:37";"2022-07-04 10:02:42"
|
||||
MEN16;"Pose de porte de garage";"Remplacement porte de garage taille standard coulissante y compris dépose et toutes sujetions de calage, fixations et équipement de quincaillerie :";0.00;507.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_16_REMPL;;;;;;;;;;MEN;"taille standard coulissante y compris";"dépose et toutes sujetions de";"calage, fixations et équipement de";"quincaillerie :";"2020-03-16 15:20:29";"2022-07-04 11:51:12"
|
||||
MEN17;"Pose de porte de garage";"Remplacement porte de garage sectionnelle taille standard y compris dépose et toutes sujétions de calage fixations et équipement de quincaillerie";0.00;578.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_17_REMPL;;;;;;;;;;MEN;"sectionnelle taille standard y compris";"dépose et toutes sujétions de calage";"fixations et équipement de quincaillerie";;"2019-09-13 16:44:03";"2022-07-04 11:52:05"
|
||||
MEN18;"Pose de porte de garage basculante";"Remplacement porte de garage basculante taille standard avec ou sans débordement y compris dépose et toutes sujetions de calage, fixation et équipement de quincaillerie :";0.00;466.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_18_REMPL;;;;;;;;;;MEN;"taille standard avec ou sans débordement";" y compris dépose et toutes sujetions de";"calage, fixation et équipement de";"quincaillerie :";"2019-07-16 17:06:49";"2022-07-04 11:52:22"
|
||||
MEN24;"Dépose et repose ou remplacement ";"Dépose et repose ou remplacement de tout type de volets roulants manuels Surface inférieure à 2 m² / hors fourniture :";0.00;167.80;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_24_DEPOS;;;;;;;;;;MEN;"de tout type de volets roulants manuels";"Surface inférieure à 2 m² / hors fourniture :";;;"2019-09-05 08:55:51";"2022-07-04 10:04:34"
|
||||
MEN25;"Dépose et repose ou remplacement";"Dépose et repose ou remplacement de tout type de volets roulants manuels Surface entre 2 et 4 m² / hors fourniture :";0.00;248.90;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_25_DEPOS;;;;;;;;;;MEN;"de tout type de volets roulants manuels";"Surface entre 2 et 4 m² / hors fourniture :";;;"2019-09-05 09:25:53";"2022-07-04 10:04:46"
|
||||
MEN26;"Dépose et repose ou remplacement de tout ";"Dépose et repose ou remplacement de tout type de volets roulants électriques, surface infé 2m², hors fournitures avec conservation des branchements existants :";0.00;185.10;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_26_DEPOS;;;;;;;;;;MEN;"type de volets roulants électriques, surface ";"infé 2m², hors fournitures avec conservation";"des branchements existants :";;"2019-07-16 16:51:10";"2022-07-04 10:04:58"
|
||||
MEN27;"Dépose et repose ou remplacement de ";"Dépose et repose ou remplacement de tout type de volets roulants électrique surf entre 2 et 4 m² hors fournitures avec conservation des branchements existants :";0.00;274.90;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_27_DEPOS;;;;;;;;;;MEN;"tout type de volets roulants électrique";"surf entre 2 et 4 m² hors fournitures avec";"conservation des branchements existants :";;"2019-07-16 16:46:04";"2022-07-04 10:05:09"
|
||||
MEN28;"Dépose et repose ou remplacement";NULL;0.00;89.80;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_28_DEPOS;;;;;;;;;;T;"de tout type de volets battants";"à l'unité par volet y compris";"scellements, réglages, ajustages";"hors fourniture :";"2021-08-05 16:05:45";"2022-07-04 10:05:18"
|
||||
MEN30;"Reprise sur PVC de < 3 impacts, ";"Reprise sur PVC de < 3 impacts, trous, éclats sur un ou plusieurs ouvrages, y compris toutes sujetions thermo-reprofilage, dépose et repose, nettoyage, ponçage :";0.00;220.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_30_REPRI;;;;;;;;;;MEN;"trous, éclats sur un ou plusieurs ";"ouvrages, y compris toutes sujetions";"thermo-reprofilage, dépose et";"repose, nettoyage, ponçage :";"2020-07-23 16:49:04";"2020-07-23 16:54:25"
|
||||
MEN31;"Reprise sur PVC, > 4 et <6 impacts, ";"Reprise sur PVC, > 4 et <6 impacts, trous, éclats sur ouvrage, y compris toutes sujétions thermo reprofilage Dépose et repose éventuelles, nettoyages, ponçages, lustrage :";0.00;451.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_31_REPRI;;;;;;;;;;MEN;"trous, éclats sur ouvrage, y compris";"toutes sujétions thermo reprofilage";"Dépose et repose éventuelles, ";"nettoyages, ponçages, lustrage :";"2020-02-13 09:56:20";"2020-02-13 09:59:07"
|
||||
MEN32;"Reprise sur PVC > 7 impacts,";NULL;0.00;671.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_32_REPRI;;;;;;;;;;MEN;"trous, éclats sur un ou plusieurs";"ouvrages, y compris toutes sujétions";"thermo-reprofilage, dépose et repose,";"nettoyage, lustrages :";"2020-12-07 16:22:57";"2020-12-07 16:26:30"
|
||||
MEN35;"Remplacement de tout type de joint";NULL;0.00;59.60;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_35_REM;;;;;;;;;;MEN;"d'étanchéité par vantail de fenêtre,";"porte-fenêtre, porte :";;;"2020-12-07 16:27:37";"2022-07-04 10:05:43"
|
||||
MEN38;"Réparation sur menuiserie alu";NULL;0.00;850.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_38_REPA;;;;;;;;;;MEN;"d'enfoncements de matières :";;;;"2022-10-19 16:41:20";"2022-10-26 11:44:48"
|
||||
MEN4;"Remplacement d'un bloc porte";"Remplacement d'un bloc porte d'entrée en maison sur cadre existant y compris dépose, pose verrous et/ou serrures, réglages ajustage et toutes sujétions :";0.00;258.40;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_4_REMP;;;;;;;;;;MEN;"d'entrée en maison sur cadre";"existant y compris dépose, pose";"verrous et/ou serrures, réglages";"ajustage et toutes sujétions :";"2020-01-08 16:14:58";"2022-07-04 10:05:58"
|
||||
MEN5;"Remplacement bloc porte d'entrée sur";"Remplacement bloc porte d'entrée sur cadre existant, y compris dépose, pose de verrous et/ou serrures, réglages, ajustages hors fourniture :";0.00;186.30;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_5_REMPL;;;;;;;;;;MEN;"cadre existant, y compris dépose, pose de";"verrous et/ou serrures, réglages, ajustages";"hors fourniture :";;"2019-11-14 08:50:42";"2022-07-04 10:06:08"
|
||||
MEN6;"Remplacement bloc porte d'entrée de";"Remplacement bloc porte d'entrée de cave, y compris dépose, scellements pose de verrous et/ou serrures réglages, ajustage, hors fourniture :";0.00;131.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_6_REMPL;;;;;;;;;;MEN;"cave, y compris dépose, scellements";"pose de verrous et/ou serrures";"réglages, ajustage, hors fourniture :";;"2019-11-14 08:44:13";"2022-07-04 10:06:19"
|
||||
MEN7;"Remplacement d'un montant dormant";"Remplacement d'un montant dormant de l'huisserie d'une porte ou porte fenêtre y compris dépose, scellements, réglages ajustages, repose, fournitures :";0.00;249.90;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_7_REMPL;;;;;;;;;;MEN;"de l'huisserie d'une porte ou porte fenêtre";"y compris dépose, scellements, réglages";"ajustages, repose, fournitures :";;"2019-11-14 08:46:49";"2022-07-04 10:06:29"
|
||||
MEN9;"Remplacement de porte-fenêtre";"Remplacement de porte-fenêtre 2 vantaux sur cadre existant y compris dépose, réglages, ajustages, hors fourniture :";0.00;238.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MEN_9_REMPL;;;;;;;;;;MEN;"2 vantaux sur cadre existant y compris";"dépose, réglages, ajustages, hors";"fourniture :";;"2019-11-27 15:14:28";"2022-07-04 10:06:47"
|
||||
MEZ;MEZZANINE;"MEZZANINE =========";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;=========;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
MIR0;"Prestations hors référentiel";"Prestations hors référentiel tarifaire :";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MIR_0_HORBPU;;;;;;;;;;MIR;"tarifaire :";;;;"2019-12-13 11:09:45";"2020-03-12 17:10:15"
|
||||
MIR24;"Remplacement double vitrage";"Remplacement double vitrage isolants préfabriqués une face clair ep.04 mm y compris traitement des déchets :";0.00;101.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MIR_24_DOUBL;;;;;;;;;;MIR;"isolants préfabriqués une face";"clair ep.04 mm y compris";"traitement des déchets :";;"2020-02-21 08:42:34";"2022-07-04 10:10:53"
|
||||
MIR25;"Remplacement d'un double vitrage";NULL;0.00;132.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MIR_25_REMPL;;;;;;;;;;MIR;"isolants préfabriqués une face";"clair ep. 5 ou 6 mm y compris";"intercalaires :";;"2021-05-25 08:46:17";"2022-09-20 16:24:39"
|
||||
MIR26;"Remplacement double vitrage isolant";"Remplacement double vitrage isolant préfabriqué ep. 08 mm y compris traitements des déchets :";0.00;159.20;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MIR_26_DOUBL;;;;;;;;;;MIR;"préfabriqué ep. 08 mm y compris";"traitements des déchets :";;;"2020-01-08 14:31:06";"2022-07-04 10:11:08"
|
||||
MIR27;"Remplacement double vitrage ";NULL;0.00;190.80;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MIR_27_DOUB;;;;;;;;;;MIR;"isolants 1 face claire ép. 8 mm :";;;;"2022-10-07 08:47:45";"2022-10-07 08:50:19"
|
||||
MIR28;"Plus value pour protection";"Plus value pour protection thermique :";0.00;25.90;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MIR_28_PLUVA;;;;;;;;;;MIR;"thermique :";;;;"2020-01-08 14:34:00";"2022-07-04 10:11:20"
|
||||
MIR29;"Plus value pour remplissage gaz";"Plus value pour remplissage gaz argon :";0.00;5.60;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MIR_29_PLUSV;;;;;;;;;;MIR;"argon : ";;;;"2020-02-21 08:44:47";"2022-07-04 10:11:35"
|
||||
MIR44;"Déplacement, prise de mesure,";"Forfait déplacement, prise de mesure, mesure, déplacement inclus hors urgence et fermeture provisoire :";0.00;41.60;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MIR_44_FORF;;;;;;;;;;MIR;"hors urgence et fermetures provisoires :";;;;"2020-08-03 15:29:15";"2022-09-20 16:30:44"
|
||||
MIR45;"Déplacement pose glace inférieure";NULL;0.00;59.60;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MIR_45_FORF;;;;;;;;;;MIR;"à 2 m² hors urgences et fermetures";"provisoires :";;;"2022-09-20 16:22:07";"2022-09-20 16:27:02"
|
||||
MIR51;"Remplacement vitrage feuilletés";"Remplacement vitrage feuilletés 33-2, y compris traitement des déchets :";0.00;198.50;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MIR_51_VITRF;;;;;;;;;;MIR;"33-2, y compris traitement des";"déchets :";;;"2020-08-03 15:32:59";"2022-07-04 10:15:24"
|
||||
MIR52;"Remplacement vitrage feuilletés";"Mise en sécurité d'une porte fenêtre par pose d'un contre plaqué ou d'un film armé y compris déplacement et traitement des déchets :";0.00;216.90;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;MIR_52_VITRF;;;;;;;;;;MIR;"44-2 y compris démasticage :";;;;"2020-02-21 08:46:02";"2022-07-04 10:16:45"
|
||||
MO;"Fourniture et pose de molleton :";"Fourniture et pose de molleton :";23.00;23.00;23.00;23.00;23.00;23.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PP;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
MP;"Murs et plafond";"Murs et plafond ---------------";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;---------------;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
MPB;"Murs, plafond et boiseries";"Murs, plafond et boiseries --------------------------";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;--------------------------;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
P;Plafond;"Plafond -------";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;-------;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
PAR0;"Prestations hors référentiel ";"Prestations hors référentiel tarifaire :";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PAR_0_HORBPU;;;;;;;;;;PAR;"tarifaire :";;;;"2019-06-19 12:01:07";"2020-03-12 17:10:26"
|
||||
PAR10;"Fourniture de sous couche :";NULL;0.00;2.80;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PAR_10_FOUR;;;;;;;;;;PAR;;;;;"2021-09-06 08:58:56";"2022-07-04 10:17:24"
|
||||
PAR11;"Remplacement parquet flottant ou";"Remplacement parquet flottant ou stratifié, dépose, évacuation, pose y compris sous couche :";0.00;34.60;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PAR_11_REMPL;;;;;;;;;;PAR;"stratifié, dépose, évacuation, pose y ";"compris sous couche :";;;"2019-06-19 11:53:55";"2022-07-04 10:17:38"
|
||||
PAR12;"Fourniture parquet stratifié ";"Fourniture parquet stratifié classique :";0.00;17.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PAR_12_FOURN;;;;;;;;;;PAR;"classique :";;;;"2019-09-19 10:34:52";"2022-07-04 10:17:48"
|
||||
PAR15;"Fourniture et pose de barre de";"Fourniture et pose de barre de seuil :";0.00;16.80;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PAR_15_BARRE;;;;;;;;;;PAR;"seuil :";;;;"2019-06-19 14:15:31";"2022-07-04 10:18:02"
|
||||
PAR16;"Remplacement plinthes ou quart de";"Remplacement plinthes ou quart de rond, dépose, fourniture et pose :";0.00;15.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PAR_16_REMPL;;;;;;;;;;PAR;"rond, dépose, fourniture et pose :";;;;"2019-06-19 14:14:05";"2022-07-04 10:18:15"
|
||||
PAR17;"Dépose, fourniture et pose de";NULL;0.00;25.50;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PAR_17_DEPO;;;;;;;;;;PAR;"panneau de type OSB";;;;"2022-03-31 14:37:29";"2022-07-04 10:18:25"
|
||||
PAR18;"Ragréage sol y compris fournitures :";"Ragréage sol y compris fournitures :";0.00;11.90;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PAR_18_RAGRE;;;;;;;;;;PAR;;;;;"2019-07-16 17:18:57";"2022-07-04 10:18:40"
|
||||
PAR19;"Facturation minimale parquet,";"Facturation minimale parquet, toutes sujétions y compris fourniture";0.00;170.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PAR_19_FACTU;;;;;;;;;;PAR;"toutes sujétions y compris fourniture";;;;"2019-07-16 17:20:44";"2021-09-06 09:00:15"
|
||||
PAR3;"Remplacement parquet contrecollé,";"Remplacement parquet contrecollé, dépose, préparation et pose :";0.00;66.50;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PAR_3_REMPLA;;;;;;;;;;PAR;"dépose, préparation et pose :";;;;"2019-06-19 14:19:21";"2022-07-04 10:19:07"
|
||||
PAR4;"Fourniture parquet contrecollé ";"Fourniture parquet contrecollé standard :";0.00;49.70;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PAR_4_FOURN;;;;;;;;;;PAR;"standard :";;;;"2020-01-08 16:45:39";"2022-07-04 10:19:20"
|
||||
PAR6;"Remplacement parquet massif";NULL;0.00;59.80;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PAR_6_REMP;;;;;;;;;;PAR;"sur lambourdes y compris dépose";"et pose du parquet :";;;"2020-12-07 16:16:44";"2022-07-04 10:19:32"
|
||||
PAR7;"Fourniture parquet lame bois massif";"Fourniture parquet lame bois massif en chêne :";0.00;99.40;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PAR_7_FOURNI;;;;;;;;;;PAR;"en chêne :";;;;"2019-06-19 14:11:59";"2022-07-04 10:19:47"
|
||||
PAR8;"Fourniture parquet lames bois massif";"Fourniture parquet lames bois massif en pin :";0.00;60.10;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PAR_8_FOURNI;;;;;;;;;;PAR;"en pin :";;;;"2019-06-19 14:10:34";"2022-07-04 10:20:01"
|
||||
PAR9;"Vitrification du parquet y compris ";"Vitrification du parquet y compris ponçage et préparations :";26.50;36.90;26.50;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PAR_9_VITRIF;;;;;;;;;;PAR;"ponçage et préparations :";;;;"2019-06-19 14:21:47";"2022-07-04 10:20:14"
|
||||
PAV;"Ponçage, affleurage, vernissage :";"Ponçage, affleurage, vernissage :";26.93;26.93;27.20;23.00;25.20;22.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;SOL;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
PD;"Pose collée de dalles :";"Pose collée de dalles :";12.00;17.60;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;SOL;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
PEE;"Piquage, effeuillage, encollage :";"Piquage, effeuillage, encollage :";23.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PLA;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
PEN0;"Prestations hors référentiel";"Prestations hors référentiel tarifaire :";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_0_HORBPU;;;;;;;;;;PEI;"tarifaire :";;;;"2020-01-08 11:07:47";"2020-03-12 17:10:35"
|
||||
PEN10;"Peinture porte par face, huisserie et ";"Peinture porte 2 faces, huisserie et boiseries ou radiateur :";0.00;40.40;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_10_PEINT;;;;;;;;;;PEI;"boiseries ou radiateur :";;;;"2019-11-20 17:35:07";"2022-07-04 10:20:47"
|
||||
PEN11;"Mise en peinture radiateur";NULL;0.00;78.20;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_11_PEINT;;;;;;;;;;PEI;"fonte :";;;;"2021-09-06 08:52:52";"2022-07-04 10:20:59"
|
||||
PEN13;"Dépose et pose de revêtement de sol,";"Dépose et pose de revêtement de sol, préparation du support :";0.00;18.80;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_13_MOQU;;;;;;;;;;SOL;"préparation du support :";;;;"2019-10-21 09:20:58";"2022-07-04 10:21:10"
|
||||
PEN17;"Remplacement de plinthes ou quart de";"Remplacement de plinthes ou quart de rond, dépose, fourniture et pose :";0.00;14.40;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_17_REMPL;;;;;;;;;;SOL;"rond, dépose, fourniture et pose :";;;;"2019-10-21 09:22:26";"2022-07-04 10:21:23"
|
||||
PEN18;"Dépose, fourniture et pose de barre";"Dépose, fourniture et pose de barre de seuil :";0.00;14.60;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_18_BARRE;;;;;;;;;;SOL;"de seuil :";;;;"2019-10-21 09:23:32";"2022-07-04 10:21:39"
|
||||
PEN2;"Mise en peinture sur murs y compris";"Mise en peinture sur murs y compris reprise d'enduit, et préparations :";0.00;20.70;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_2_MISEEN;;;;;;;;;;PEI;"reprise d'enduit, et préparations :";;;;"2019-10-21 08:59:25";"2022-07-04 10:21:49"
|
||||
PEN21;"Facturation minimale peinture, ";"Facturation minimale peinture, toutes sujétions y compris fourniture :";0.00;310.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_21_FACTU;;;;;;;;;;PEI;"toutes sujétions y compris ";"fournitures :";;;"2020-02-13 10:03:25";"2022-02-16 11:27:17"
|
||||
PEN22;"Rebouchage des fissures, grattage,";"Rebouchage des fissures, grattage, reprise d'enduit :";0.00;21.20;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_22_REBOU;;;;;;;;;;PLA;"reprise d'enduit :";;;;"2019-10-21 09:19:04";"2022-07-04 10:22:08"
|
||||
PEN3;"Mise en peinture sur plafond y ";"Mise en peinture sur plafond y compris préparations des fonds :";0.00;22.30;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_3_MISEEN;;;;;;;;;;PEI;"compris préparations des fonds :";;;;"2019-10-21 09:02:10";"2022-07-04 10:22:17"
|
||||
PEN4;"Application de peinture projetée";"Application de peinture projetée type gouttelette sur murs et/ou plafond, intégrant grattage, rebouchage, enduit et ponçage :";0.00;31.20;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_4_APPLIC;;;;;;;;;;PEI;"type gouttelette sur murs et/ou";"plafond, intégrant grattage,";"rebouchage, enduit et ponçage :";;"2020-06-30 08:41:24";"2022-07-04 10:22:35"
|
||||
PEN6;"Remplacement de toile de verre, remise";"Remplacement de toile de verre, remise en peinture y compris arrachage de la toile, et préparations des fonds";0.00;33.20;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_6_REMPL;;;;;;;;;;PEI;"en peinture y compris arrachage de la";"toile et préparations des fonds";;;"2019-10-21 09:13:10";"2022-07-04 10:22:45"
|
||||
PEN7;"Remplacement du papier peint y compris";"Remplacement du papier peint y compris arrachage et préparations :";0.00;20.10;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_7_REMPL;;;;;;;;;;PP;"arrachage et préparations : ";;;;"2019-10-21 09:15:26";"2022-07-04 10:22:55"
|
||||
PEN8;"Fourniture papier peint classique :";"Fourniture papier peint classique :";0.00;19.30;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_8_FOURN;;;;;;;;;;PP;;;;;"2019-10-21 09:17:07";"2022-02-07 09:28:06"
|
||||
PEN9;"Mise en peinture des plinthes ou ";"Mise en peinture des plinthes ou canalisation :";0.00;6.30;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_9_PEINT;;;;;;;;;;PEI;"canalisation :";;;;"2019-10-21 09:18:01";"2022-07-04 10:23:10"
|
||||
PF;"Préparations des fonds :";"Préparations des fonds :";8.50;6.02;0.00;8.28;0.00;0.00;6.50;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;SOL;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
PFR;"Pose de frise :";"Pose de frise :";10.00;10.00;3.60;10.00;10.00;10.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;ML;PNT;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
PG;"Peinture laque brillante sur";"Peinture laque brillante sur préparations :";28.00;18.60;20.90;23.60;23.50;20.00;34.00;0.00;0.00;0.00;;;;;;;;;;;;PEI;"préparations :";;;;"2017-08-15 09:18:37";"2022-10-20 15:45:31"
|
||||
PIF;"Peinture d'impression des fonds :";"Peinture d'impression des fonds :";12.96;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PEI;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
PL;"Mise en peinture des plinthes ou";"Mise en peinture des plinthes ou tuyaux :";0.00;6.30;6.70;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_9_PEINTU;;;;;;;;;;PEI;"tuyaux :";;;;"2019-06-12 12:06:07";"2022-07-08 16:12:47"
|
||||
PLA;Placard;"Placard -------";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;-------;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
PLA0;"Prestations hors référentiel";"Prestations hors référentiel tarifaire :";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PLA_0_HORBPU;;;;;;;;;;PLA;"tarifaire :";;;;"2019-10-25 16:12:14";"2020-03-12 17:10:44"
|
||||
PLA12;"Remplacement faux plafond en BA13";"Remplacement faux plafond en BA13 sur ossature conservée, dépose, évacuation, fourniture et pose y compris bandes :";0.00;37.20;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PLA_12_REMPL;;;;;;;;;;PLA;"sur ossature conservée, dépose,";"évacuation, fourniture et pose y compris";"bandes :";;"2019-10-25 16:08:15";"2022-07-04 10:23:34"
|
||||
PLA13;"Remplacement faux plafond BA13";"Remplacement faux plafond BA13 y compris ossature métallique, dépose, évacuation, fourniture et pose y compris bandes :";0.00;53.50;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PLA_13_REMPL;;;;;;;;;;PLA;"y compris ossature métallique, dépose,";"évacuation, fourniture et pose y compris";"bandes :";;"2019-10-25 16:10:38";"2022-07-04 10:23:44"
|
||||
PLA14;"Remplacement dalles suspendues";"Remplacement dalles suspendues sur ossature métallique conservée, dépose, évacuation, fourniture et pose :";0.00;26.50;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PLA_14_REMPL;;;;;;;;;;PLA;"sur ossature métallique conservée,";"dépose, évacuation, fourniture et";"pose :";;"2020-03-16 10:22:27";"2022-07-04 10:23:53"
|
||||
PLA15;"Remplacement dalles suspendues";"Remplacement dalles suspendues y compris ossature métallique apparente, dépose, évacuation, fourniture et pose :";0.00;53.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PLA_15_REMPL;;;;;;;;;;PLA;"y compris ossature métallique";"apparente, dépose, évacuation,";"fourniture et pose :";;"2020-03-16 10:20:58";"2022-07-04 10:24:01"
|
||||
PLA16;"Remplacement isolant en plafond";"Remplacement isolant en plafond ép. jusqu'à 240 mm, dépose, évacuation, fourniture et pose :";0.00;25.30;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PLA_16_REMPL;;;;;;;;;;PLA;"ép. jusqu'à 240 mm, dépose,";"évacuation, fourniture et pose :";;;"2020-08-03 09:56:01";"2022-07-04 10:24:16"
|
||||
PLA17;"Reconstitution de plâtre manuel ";NULL;0.00;24.40;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PLA_17_RECON;;;;;;;;;;PLA;"sur support brut sur murs et plafonds :";;;;"2022-02-08 16:23:05";"2022-07-04 10:26:46"
|
||||
PLA5;"Remplacement de cloison ou doublage";"Remplacement de cloison ou doublage en plaques de plâtre BA 13 sur ossature conservée, dépose, fourniture et pose y compris bande :";0.00;32.60;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PLA_5_REMPL;;;;;;;;;;PLA;"en plaques de plâtre BA 13 sur ossature";"conservée, dépose, fourniture et pose";"y compris bande :";;"2019-10-25 15:56:59";"2022-07-04 10:27:00"
|
||||
PLA6;"Remplacement doublage en plaques";"Remplacement doublage en plaques de plâtre type BA13 sur rails y compris ossature métallique, dépose, évacuation, fourniture et pose :";0.00;50.30;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PLA_6_REMPL;;;;;;;;;;PLA;"de plâtre type BA13 sur rails y";"compris ossature métallique, dépose,";"évacuation, fourniture et pose :";;"2019-10-25 15:58:56";"2022-07-04 10:27:12"
|
||||
PLA7;"Remplacement cloison type BA13 Placostil";"Remplacement cloison type BA13 Placostil y compris ossature métallique, dépose, évacuation, fourniture et pose :";0.00;59.80;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PLA_7_REMPL;;;;;;;;;;PLA;"y compris ossature métallique, dépose,";"évacuation, fourniture et pose :";;;"2019-10-25 16:02:42";"2022-07-04 10:27:34"
|
||||
PLA9;"Plus value hydrofuges pour plaques";"Plus value hydrofuges pour plaques de plâtre type BA13 :";0.00;3.30;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PLA_9_PLUSV;;;;;;;;;;PLA;"de plâtre type BA13 :";;;;"2020-02-21 15:52:02";"2022-07-04 10:29:14"
|
||||
PLAT;PLATRERIE;"PLATRERIE =========";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;=========;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
PLI;Plinthes;"Plinthes --------";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;--------;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
PLO14;"Dépose et repose de sanitaires";NULL;0.00;155.60;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PLO_14_DEPO;;;;;;;;;;PLO;"scellés y compris accessoires";"et protections :";;;"2022-11-09 09:47:58";"2022-11-09 09:51:29"
|
||||
PLO7;"Travaux de réparations réseau";NULL;0.00;47.70;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PLO7;;;;;;;;;;PLO;"d'alimentation en cuivre :";;;;"2022-11-09 09:51:36";"2022-11-09 09:52:49"
|
||||
PLP033;"Entoilage :";NULL;0.00;0.00;0.00;0.00;0.00;0.00;5.95;0.00;0.00;0.00;;;;;;;PLP033;;;;;PP;;;;;"2021-11-30 17:16:55";"2021-11-30 17:18:09"
|
||||
PLP034;"Peinture de sol :";NULL;0.00;0.00;0.00;0.00;0.00;0.00;12.75;0.00;0.00;0.00;;;;;;;PLP034;;;;;PEI;;;;;"2021-11-30 17:20:02";"2021-11-30 17:21:01"
|
||||
PLP047;"Murs : Lessivage + Masticage +";NULL;0.00;0.00;0.00;0.00;0.00;0.00;5.95;0.00;0.00;0.00;;;;;;;PLP047;;;;;PEI;"Peinture satinée à 2 couches :";;;;"2021-11-30 17:18:39";"2021-11-30 17:19:50"
|
||||
PLP093;"Plafond : Dépose dalles polystyrène +";NULL;0.00;0.00;0.00;0.00;0.00;0.00;10.19;0.00;0.00;0.00;;;;;;;PLP093;;;;;PEI;"Masticage + Raccord plâtre +";"Peinture glycéromate à 2 couches :";;;"2021-11-30 17:11:02";"2021-11-30 17:14:31"
|
||||
PLP130;"Dépose et évacuation lambris";NULL;0.00;0.00;0.00;0.00;0.00;0.00;8.50;0.00;0.00;0.00;;;;;;;PLP130;;;;;MEN;"compris ossature :";;;;"2021-11-30 17:15:05";"2021-11-30 17:16:33"
|
||||
PLP168;"Réfection complète d'un séjour :";NULL;0.00;0.00;0.00;0.00;0.00;0.00;475.57;0.00;0.00;0.00;;;;;;;PLP168;;;;;PEI;;;;;"2021-11-16 15:23:35";"2021-11-16 15:24:26"
|
||||
PLP169;"Réfection complète d'une ";NULL;0.00;0.00;0.00;0.00;0.00;0.00;356.68;0.00;0.00;0.00;;;;;;;PLP169;;;;;PEI;"chambre :";;;;"2021-11-16 15:24:41";"2021-11-16 15:25:41"
|
||||
PLP170;"Réfection complète Entrée";"1 face ------";0.00;0.00;0.00;0.00;0.00;0.00;174.10;0.00;0.00;0.00;;;;;;;PLP170;;;;;PEI;"ou petit dégagement :";;;;"2017-08-15 09:18:37";"2021-11-16 15:28:19"
|
||||
PLP171;"Réfection complète d'un grand";NULL;0.00;0.00;0.00;0.00;0.00;0.00;207.22;0.00;0.00;0.00;;;;;;;PLP171;;;;;PEI;"dégagement :";;;;"2021-11-16 15:30:44";"2021-11-16 15:31:40"
|
||||
PLP172;"Réfection complète de la";NULL;0.00;0.00;0.00;0.00;0.00;0.00;386.41;0.00;0.00;0.00;;;;;;;PLP172;;;;;PEI;"cuisine :";;;;"2021-11-16 15:31:44";"2021-11-16 15:32:24"
|
||||
PLP173;"Réfection complète de la salle";NULL;0.00;0.00;0.00;0.00;0.00;0.00;245.43;0.00;0.00;0.00;;;;;;;PLP173;;;;;PEI;"de bains :";;;;"2021-11-16 15:32:34";"2021-11-16 15:33:13"
|
||||
PLP174;"Réfection complète des";NULL;0.00;0.00;0.00;0.00;0.00;0.00;150.32;0.00;0.00;0.00;;;;;;;PLP174;;;;;PEI;"toilettes :";;;;"2021-11-16 15:33:18";"2021-11-16 15:34:05"
|
||||
PLP177;"Réfection totale d'un logement";NULL;0.00;0.00;0.00;0.00;0.00;0.00;1698.47;0.00;0.00;0.00;;;;;;;"PLP177 ";;;;;PEI;"de type 1 :";;;;"2021-11-16 14:52:02";"2021-11-16 15:10:50"
|
||||
PLP178;"Réfection totale d'un logement";NULL;0.00;0.00;0.00;0.00;0.00;0.00;2123.09;0.00;0.00;0.00;;;;;;;PLP178;;;;;PEI;"de type T2 ou T1B :";;;;"2021-11-16 15:11:16";"2021-11-16 15:12:50"
|
||||
PLP179;"Réfection totale d'un logement";NULL;0.00;0.00;0.00;0.00;0.00;0.00;2554.43;0.00;0.00;0.00;;;;;;;PLP179;;;;;PEI;"de type T3 ou T2B :";;;;"2021-11-16 15:13:52";"2022-03-30 15:34:32"
|
||||
PLP180;"Réfection totale d'un logement";NULL;0.00;0.00;0.00;0.00;0.00;0.00;2802.48;0.00;0.00;0.00;;;;;;;PLP180;;;;;PEI;"de type T4 ou T3B :";;;;"2021-11-16 15:15:49";"2021-12-01 08:55:47"
|
||||
PLP181;"Réfection totale d'un logement";NULL;0.00;0.00;0.00;0.00;0.00;0.00;3227.09;0.00;0.00;0.00;;;;;;;PLP181;;;;;PEI;"de type T5 ou T4B :";;;;"2021-11-16 15:17:32";"2021-11-16 15:18:43"
|
||||
PLP182;"Réfection totale d'un logement";NULL;0.00;0.00;0.00;0.00;0.00;0.00;3481.86;0.00;0.00;0.00;;;;;;;PLP182;;;;;PEI;"de type T6";;;;"2021-11-16 15:19:21";"2021-11-16 15:20:11"
|
||||
PM;"Peinture mate sur préparations :";"Peinture mate sur préparations :";23.00;0.00;23.00;23.60;19.64;19.00;20.00;0.00;0.00;0.00;;;;PE-END01;;;;;;;;PEI;;;;;"2017-08-15 09:18:37";"2022-10-20 08:35:15"
|
||||
PMM;"Peinture mate sur murs y";"Peinture mate sur murs y compris préparations :";0.00;20.70;0.00;0.00;18.40;0.00;0.00;0.00;0.00;0.00;;PEN_2_MISEEN;;;;;;;;;;PEI;"compris préparations :";;;;"2019-06-12 11:57:10";"2022-10-20 08:36:14"
|
||||
PMP;"Peinture mate sur plafond y ";"Peinture mate sur plafond y compris préparations :";0.00;22.30;0.00;0.00;19.64;0.00;0.00;0.00;0.00;0.00;;PEN_3_MISEEN;;;;;;;;;;PEI;"compris préparations :";;;;"2019-02-08 08:22:09";"2022-10-20 08:35:45"
|
||||
PN;"Dépose de revêtement plastique";"Dépose de revêtement plastique moquette non collé et évacuation";4.80;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;SOL;"moquette non collé et évacuation";;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
PP;"Pose de papier peint sur";"Pose de papier peint sur préparations :";23.60;20.10;23.60;22.00;16.15;20.50;19.00;0.00;0.00;0.00;;PEN_7_REMPLA;;;;;;;;;;PNT;"préparations :";;;;"2017-08-15 09:18:37";"2022-10-20 15:46:35"
|
||||
PPP;"Pose de papier à peindre sur";"Pose de papier à peindre sur préparations :";18.50;0.00;0.00;33.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PNT;"préparations :";;;;"2017-08-15 09:18:37";"2018-05-17 07:46:40"
|
||||
PPR;"PIECE PRINCIPALE";"PIECE PRINCIPALE ================";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;================;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
PR;"Pose de revêtement de sol collé :";"Pose de revêtement de sol collé :";9.00;0.00;14.08;10.35;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;SOL;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
PRE;"Raclage, ratissage sur parties";"Raclage, ratissage sur parties écaillées :";0.00;0.00;0.00;0.00;0.00;38.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PLA;"écaillées :";;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
PRO;"Protection et nettoyage :";"Protection et nettoyage :";0.00;3.58;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;;;;;;;;;;;PNT;;;;;"2017-08-15 09:18:37";"2020-05-07 10:53:00"
|
||||
PROT;"Protection et nettoyage sur l'ensemble";"Protection et nettoyage sur l'ensemble";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PNT;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
PS;"Peinture satinée ou semibrillante sur";"Peinture satinée ou semibrillante sur préparations :";23.00;0.00;23.00;23.60;19.64;20.00;20.00;0.00;0.00;0.00;;;;;;;;;;;;PEI;"préparations :";;;;"2017-08-15 09:18:37";"2022-10-20 15:44:51"
|
||||
PSB;"Peinture satinée sur boiseries";"Peinture satinée sur boiseries";0.00;0.00;33.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;;;;;;;;;;;PEI;;;;;"2020-02-21 09:06:13";"2020-02-21 09:06:42"
|
||||
PSM;"Peinture satinée sur préparations :";"Peinture satinée sur préparations :";0.00;20.70;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_2_MISEEN;;;;;;;;;;PEI;;;;;"2019-06-12 12:00:14";"2022-07-08 15:47:30"
|
||||
PT;"Plafond et retombées";"Plafond et retombées --------------------";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;--------------------;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
R;"Rechampis du pourtour :";"Rechampis du pourtour :";1.50;1.50;1.50;1.50;1.50;1.50;1.50;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;0;PNT;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
RA;"Ratissage à 2 passes, ponçage :";"Ratissage à 2 passes, ponçage :";15.24;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PEI;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
RBA;"Fourniture et pose de faux plafond :";"Fourniture et pose de faux plafond :";52.00;48.00;45.50;41.40;52.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PLA;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
RDC;"REZ DE CHAUSSEE";"REZ DE CHAUSSEE ===============";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;===============;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
RDF1;"Forfait RDF simple :";NULL;155.00;0.00;155.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;;;;;;;;;;;AR;;;;;"2019-06-20 16:58:30";"2022-02-07 13:48:44"
|
||||
RDF2;"Forfait RDF spécialisée :";NULL;484.00;0.00;484.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;;;;;;;;;;;;;;;;"2019-06-20 16:58:30";"2022-02-07 13:48:33"
|
||||
RE4;"Remise 4 % :";"Remise 4 % :";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;;;;;;;;;;;T;;;;;"2020-02-04 15:28:31";"2020-02-04 15:28:56"
|
||||
RE6;"Remise 6 % :";"Remise 6 % :";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;;;;;;;;;;;T;;;;;"2020-02-04 15:28:04";"2020-02-04 15:29:21"
|
||||
REP;"Raclage, ratissage sur parties";"Raclage, ratissage sur parties écaillées :";0.00;0.00;0.00;0.00;0.00;38.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;0;PLA;"écaillées :";;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
RL;"Ragréage, Lissage";"Ragréage, Lissage";23.00;9.60;0.00;12.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;SOL;;;;;"2017-08-15 09:18:37";"2018-08-07 14:47:27"
|
||||
RO;"Fourniture et pose de laine de verre";"Fourniture et pose de laine de verre ou laine de roche :";25.00;25.00;25.00;25.00;25.00;25.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PLA;"ou laine de roche :";;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
RSBASE;"Fourniture et pose de barre de seuil :";NULL;0.00;0.00;0.00;14.10;0.00;0.00;0.00;0.00;0.00;0.00;;;;RS-BASEU;;;;;;;;PAR;;;;;"2022-10-03 08:59:07";"2022-10-03 08:59:57"
|
||||
RSPACL;"Dépose et remplacement de parquet";NULL;0.00;0.00;0.00;71.10;0.00;0.00;0.00;0.00;0.00;0.00;;;;RS-PACLO;;;;;;;;PAR;"cloué sur lambourdes, y compris";"préparations :";;;"2022-10-03 08:57:46";"2022-10-19 16:43:26"
|
||||
RSPAFL;"Dépose et remplacement de parquet";NULL;0.00;0.00;0.00;32.00;0.00;0.00;0.00;0.00;0.00;0.00;;;;RS-PAFLO;;;;;;;;PAR;"flottant avec feutre, y compris préparation";"des supports et pose :";;;"2022-10-19 16:35:03";"2022-10-19 16:41:11"
|
||||
RSPLIN;"Remplacement de plinthes bois";NULL;0.00;0.00;0.00;12.10;0.00;0.00;0.00;0.00;0.00;0.00;;;;RS-PLIN;;;;;;;;PAR;"ou PVC :";;;;"2022-10-03 08:56:39";"2022-10-03 08:57:35"
|
||||
RSPVVI;"Ponçage et vitrification de parquet";NULL;0.00;0.00;0.00;35.00;0.00;0.00;0.00;0.00;0.00;0.00;;;;RS-PVVIT;;;;;;;;PAR;"en complément au delà des 12 m² :";;;;"2022-10-03 08:54:37";"2022-10-03 08:56:21"
|
||||
RSVITR;"Ponçage et vitrification de parquet";NULL;0.00;0.00;0.00;430.00;0.00;0.00;0.00;0.00;0.00;0.00;;;;RS-VITRI;;;;;;;;PAR;"Forfait minimum < 12 m² :";;;;"2022-10-03 08:53:05";"2022-10-03 08:54:21"
|
||||
S;Sol;"Sol ---";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;---;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
SA;SALON;"SALON =====";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;=====;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
SAM;"SALLE A MANGER";"SALLE A MANGER ==============";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;==============;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
SC;"Application de sous couche spéciale";"Application de sous couche spéciale produit décoratif :";12.96;12.96;12.96;12.96;12.96;12.96;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PNT;"produit décoratif :";;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
SDB;"SALLE DE BAINS";"SALLE DE BAINS ==============";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;==============;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
SE;SEJOUR;"SEJOUR ======";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;======;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
SER0;"Prestation hors référentiel";"Prestation hors référentiel tarifaire :";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;SER_0_HORBPU;;;;;;;;;;MEN;"tarifaire :";;;;"2020-02-25 09:50:03";"2020-02-25 09:51:27"
|
||||
SER3;"Remplacement verrou ou cylindre";"Remplacement verrou ou cylindre tout type (à bouton ou double entrée y compris haute sureté, déplacement compris :";0.00;81.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;SER_3_REMPL;;;;;;;;;;MEN;"tout type (à bouton ou double entrée";"y compris haute sureté, déplacement";"compris :";;"2020-08-03 15:34:44";"2022-07-04 10:32:31"
|
||||
SER4;"Remplacement serrure mono point";"Remplacement serrure mono point tout type (à larder ou en applique) déplacement compris :";0.00;102.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;SER_4_REMP;;;;;;;;;;MEN;"tout type (à larder ou en applique)";"déplacement compris :";;;"2020-08-03 15:38:33";"2022-07-04 10:32:50"
|
||||
SLS024;"Fourniture et pose de lés vinyles";NULL;0.00;0.00;0.00;0.00;0.00;0.00;21.23;0.00;0.00;0.00;;;;;;;SLS024;;;;;SOL;"sur sol déposé :";;;;"2021-11-30 17:30:36";"2021-11-30 17:31:57"
|
||||
SM;"Shampooing de moquette :";"Shampooing de moquette :";10.00;10.00;10.00;7.87;10.00;7.40;11.50;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;SOL;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
SOL;"Dépose du revêtement de sol existant,";"Dépose du revêtement de sol existant, préparations des fonds et pose de revêtement collé :";42.10;18.80;42.10;22.00;21.69;21.00;25.50;0.00;0.00;0.00;;PEN_13_MOQU;;RS-MOPVC;;;;;;;;SOL;"préparations des fonds et pose de revêtement";"collé :";;;"2017-08-15 09:18:37";"2022-10-19 16:38:41"
|
||||
TCF;"Ce devis ne comprend pas les dommages";NULL;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;;;;;;;;;;;PEI;"en Plâtrerie Peinture occasionnés par";"la réparation de la fuite.";;;"2022-10-10 11:15:09";"2022-10-10 11:17:36"
|
||||
TD;"Traitement et valorisation des déchets";"Traitement et valorisation des déchets montant forfaitaire de 1 % :";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;GEN_0_DECHET;;;;;;;;;;T;"montant forfaitaire de 1 % :";;;;"2020-02-04 08:23:31";"2022-02-08 16:20:49"
|
||||
TT;"Pose de tissu tendu sur préparations :";"Pose de tissu tendu sur préparations :";38.00;23.87;34.03;42.30;38.00;38.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PP;;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
TV;"Fourniture et pose de toile de verre";"Fourniture et pose de toile de verre sur préparations :";23.50;8.18;10.40;0.00;23.50;0.00;20.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;PNT;"sur préparations :";;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
TVP;"Fourniture et pose de toile de verre ";"Fourniture et pose de toile de verre y compris peinture acrylique mate ou satinée :";41.40;33.20;41.40;36.00;33.15;30.00;39.00;0.00;0.00;0.00;;PEN_6_REMPLA;;;;;;;;;;PNT;"standard y compris peinture acrylique ";"mate ou satinée :";;;"2017-08-15 09:18:37";"2022-10-20 08:36:47"
|
||||
TVPS;"Fourniture et pose de toile de verre y";"Fourniture et pose de toile de verre y compris peinture acrylique satinée :";40.50;32.81;33.00;33.48;40.00;0.00;0.00;0.00;0.00;0.00;;;;;;;;;;;;PNT;"compris peinture acrylique satinée :";;;;"2017-08-15 09:18:37";"2020-02-04 08:30:50"
|
||||
U;"Mise en peinture d'uniformisation :";"Mise en peinture d'uniformisation :";15.50;12.00;15.50;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;PEN_8_MISEEN;;;;;;;;;;PEI;;;;;"2019-06-12 12:03:28";"2022-02-07 09:16:29"
|
||||
URG10;"Fermeture provisoire de porte 1 vantail";NULL;0.00;270.50;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;URG_10_FERM;;;;;;;;;;MEN;"avec du contre-plaqué rigide ou";"renforcé par des tasseaux de bois :";;;"2022-09-20 16:28:16";"2022-09-29 11:48:21"
|
||||
URG3;"Remplacement simple vitrage";"Remplacement simple vitrage clair, d'épaisseur < à 10 mm et de surface < à 1 m², y compris déplacements et traitement des déchets :";0.00;179.20;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;URG_3_REMPL;;;;;;;;;;MEN;"clair, d'épaisseur < à 10 mm et";"de surface < à 1 m², y compris";"déplacements et traitement des";"déchets :";"2020-02-25 09:51:46";"2022-07-04 10:33:13"
|
||||
VEN;"Pose d'un ventilateur :";"Pose d'un ventilateur :";15.00;0.00;15.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;;;;;;;;;;;;ASS;;;;;"2020-01-15 15:54:15";"2021-10-27 09:09:41"
|
||||
WC;W.C.;"W.C. ====";0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;0.00;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;NULL;;T;====;;;;"2017-08-15 09:18:37";"2017-08-15 09:18:37"
|
||||
|
6
cao_osint/static/uploads/dolibarr-psw.txt
Normal file
6
cao_osint/static/uploads/dolibarr-psw.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
https://caotekfr.with.multicompany.cloud/?username=admin
|
||||
admin - pcao.8211
|
||||
|
||||
http://dolibarr.driveperso.com/index.php
|
||||
caotek - q4txk0mr
|
||||
|
||||
8
cao_osint/templates/404.jinja2
Normal file
8
cao_osint/templates/404.jinja2
Normal file
@@ -0,0 +1,8 @@
|
||||
{% extends "layout.jinja2" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="content">
|
||||
<h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Starter project</span></h1>
|
||||
<p class="lead"><span class="font-semi-bold">404</span> Page Not Found</p>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
33
cao_osint/templates/apropos.jinja2
Normal file
33
cao_osint/templates/apropos.jinja2
Normal file
@@ -0,0 +1,33 @@
|
||||
{% extends "layout.jinja2" %}
|
||||
|
||||
{% block content %}
|
||||
<br />
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div class="panel panel-default text-center">
|
||||
<div class="panel-body">
|
||||
<blockquote>
|
||||
L'argent qu'on possède est l'instrument de la liberté; celui qu'on pourchasse est celui de la servitude.
|
||||
</blockquote>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<h4>Rousseau</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-5">
|
||||
<div class="panel panel-default text-center">
|
||||
<div class="panel-body">
|
||||
<blockquote>
|
||||
L'intelligence ce n'est pas ce que l'on sait mais ce que l'on fait quand on ne sait pas.
|
||||
<br />
|
||||
</blockquote>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
<h4>Jean Piaget</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
34
cao_osint/templates/blog.jinja2
Normal file
34
cao_osint/templates/blog.jinja2
Normal file
@@ -0,0 +1,34 @@
|
||||
{% extends "cao_osint:templates/layout.jinja2" %}
|
||||
|
||||
{% block content %}
|
||||
{% if request.authenticated_userid %}
|
||||
<p>
|
||||
<a href="{{ request.route_url('home') }}">[ Retour ]</a>
|
||||
<a href="{{ request.route_url('blog_edit', id=entry.id) }}">[ Modifier ]</a>
|
||||
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<hr/>
|
||||
<p>{{ body_html | safe }}</p>
|
||||
<hr/>
|
||||
<p>
|
||||
Auteur : <strong>{{ entry.author }}</strong><br>
|
||||
Publié le : <strong>{{ entry.created.strftime("%d-%m-%Y - %H:%M") }}</strong><br>
|
||||
{% if request.authenticated_userid %}
|
||||
Modifié le : <strong>{{ entry.edited.strftime("%d-%m-%Y - %H:%M") }}</strong><br>
|
||||
Tag : <strong>{{ entry.tag }}</strong><br>
|
||||
Statut : <strong>{{ entry.status }}</strong>
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<script>
|
||||
const anchors = document.querySelectorAll('a');
|
||||
anchors.forEach((a) => {
|
||||
a.setAttribute('target', '__blank');
|
||||
a.setAttribute('rel', 'noopener noreferrer');
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
80
cao_osint/templates/blog_edit.jinja2
Normal file
80
cao_osint/templates/blog_edit.jinja2
Normal file
@@ -0,0 +1,80 @@
|
||||
{% extends "cao_osint:templates/layout.jinja2" %}
|
||||
|
||||
{% block content %}
|
||||
<form action="{{ url }}" method="post" class="form">
|
||||
|
||||
{% for error in form.title.errors %}
|
||||
<div class="error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="title">{{ form.title.label }}</label>
|
||||
{{ form.title(class_='form-control') }}
|
||||
</div>
|
||||
|
||||
{% for error in form.body.errors %}
|
||||
<div class="error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="body">{{ form.body.label }}</label>
|
||||
{{ form.body(class_='form-control', cols="35", rows="20") }}
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="tag">{{ form.tag.label }}</label>
|
||||
{{ form.tag(class_='form-control') }}
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="status">{{ form.status.label }}</label>
|
||||
{{ form.status(class_='form-control') }}
|
||||
</div>
|
||||
|
||||
<p>
|
||||
{% if blog_id != '0' %}
|
||||
Créé le : <strong>{{ entry.created.strftime("%d-%m-%Y - %H:%M") }}</strong><br>
|
||||
Modifié le : <strong>{{ entry.edited.strftime("%d-%m-%Y - %H:%M") }}</strong>
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<br />
|
||||
<div class="form-group">
|
||||
<a class="btn btn-default" href="{{ request.route_url('home') }}"><span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
|
||||
<button class="btn btn-primary" type="submit" name="form.submitted">
|
||||
<span class="glyphicon glyphicon-ok"></span> Enregistrer</button>
|
||||
{% if blog_id != '0' %}
|
||||
<button class="btn btn-danger" type="button" data-toggle="modal" data-target="#confirmDelete">
|
||||
<span class="glyphicon glyphicon-remove"></span> Supprimer</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<p class="text-center">Apprendre la syntaxe de <a href="https://www.markdownguide.org/basic-syntax/" target="_blank">Markdown</a></li></p>
|
||||
|
||||
</form>
|
||||
|
||||
<!-- Modal : Confirmation SUPRESSION -->
|
||||
<div id="confirmDelete" class="modal" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">Supprimer une page</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- The form is placed inside the body of modal -->
|
||||
<p>Etes-vous certain(e) de vouloir supprimer <b><br>
|
||||
{{ entry.title }}</b> ?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="form-group">
|
||||
<div class="text-center">
|
||||
<form id="confirmForm" method="post">
|
||||
<button type="submit" class="btn btn-danger" name="form.deleted">Supprimer</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
51
cao_osint/templates/blog_search.jinja2
Normal file
51
cao_osint/templates/blog_search.jinja2
Normal file
@@ -0,0 +1,51 @@
|
||||
{% extends "cao_osint:templates/layout.jinja2" %}
|
||||
|
||||
{% block content %}
|
||||
<form id="search-form" class="form-horizontal" role="form" action="/blog_search" method="post">
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-2 col-sm-8">
|
||||
<div class="input-group" align="center">
|
||||
{{ form.criteria(class_='form-control') }}
|
||||
<span class="input-group-btn">
|
||||
<button id="submitButton" class="btn btn-primary" type="submit" name="form.submitted">
|
||||
Rechercher
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
{% for error in form.criteria.errors %}
|
||||
<div class="text-danger">{{ error }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="row">
|
||||
{% if items %}
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Titre</th>
|
||||
<th>Tags</th>
|
||||
<th>Date</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for entry in items %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ request.route_url('blog', id=entry.id, slug=entry.slug) }}">
|
||||
{{ entry.title }}
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ entry.tag }}</td>
|
||||
<td>{{ entry.edited.strftime("%d-%m-%Y - %H:%M") }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endif %}
|
||||
</div>
|
||||
<br />
|
||||
<br />
|
||||
|
||||
{% endblock %}
|
||||
54
cao_osint/templates/home.jinja2
Normal file
54
cao_osint/templates/home.jinja2
Normal file
@@ -0,0 +1,54 @@
|
||||
{% extends "layout.jinja2" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if request.authenticated_userid %}
|
||||
<p><a href="{{ request.route_url('blog_edit', id='0') }}" class="btn btn-success" role="button">
|
||||
<span class="glyphicon glyphicon-plus"></span> Nouveau</a>
|
||||
</p>
|
||||
{% endif%}
|
||||
|
||||
<table id="posts_list" class="table table-condensed">
|
||||
{% for entry in last_ten %}
|
||||
<tr>
|
||||
<td>{{ entry.created.strftime("%d.%m.%Y") }}</td>
|
||||
<td>
|
||||
<a href="{{ request.route_url('blog', id=entry.id, slug=entry.slug) }}">{{ entry.title }}</a>
|
||||
</td>
|
||||
<td>{{ entry.tag }}</td>
|
||||
{% if entry.status != 'publié' %}
|
||||
<td><span class="label label-danger">{{ entry.status }}</span></td>
|
||||
{% else %}
|
||||
<td> </td>
|
||||
{% endif%}
|
||||
</tr>
|
||||
{% else %}
|
||||
<p class="text-danger">Aucun post trouvé</p>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
<!-- formulaire de recherche -->
|
||||
<hr>
|
||||
<br>
|
||||
<br>
|
||||
<div class="well">
|
||||
|
||||
<form id="search-form" role="form" action="/blog_search" method="post">
|
||||
<div class="form-group">
|
||||
<label for="criteria">{{ form.criteria.label }}</label>
|
||||
<div class="input-group">
|
||||
{{ form.criteria(class_='form-control') }}
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-primary" type="submit" name="form.submitted">
|
||||
Rechercher
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
{% for error in form.criteria.errors %}
|
||||
<div class="text-danger">{{ error }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
114
cao_osint/templates/layout.jinja2
Normal file
114
cao_osint/templates/layout.jinja2
Normal file
@@ -0,0 +1,114 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="pyramid web application">
|
||||
<link rel="shortcut icon" href="{{request.static_url('cao_osint:static/pyramid-16x16.png')}}">
|
||||
|
||||
<title>{{page_title}}</title>
|
||||
|
||||
<!-- Bootstrap core CSS -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
|
||||
|
||||
<!-- Custom styles for this scaffold -->
|
||||
<link href="{{request.static_url('cao_osint:static/theme.css')}}" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-default navbar-fixed-top">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#myNavbar">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="{{ request.route_url('home') }}">CAO Blogr</a>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse" id="myNavbar">
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="{{ request.route_url('blog_search') }}"><span class="glyphicon glyphicon-search"></span></a></li>
|
||||
{% if request.authenticated_userid %}
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">{{request.authenticated_userid}}
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
{% if request.authenticated_userid == 'admin' %}
|
||||
<li><a href="{{request.route_url('users')}}"><span class="glyphicon glyphicon-user"></span> Utilisateurs</a></li>
|
||||
{% else %}
|
||||
<li><a href="{{request.route_url('user_edit', name=request.authenticated_userid)}}">
|
||||
<span class="glyphicon glyphicon-user"></span> Modifier le mot de passe</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li><a href="{{ request.route_url('tags') }}"><span class="glyphicon glyphicon-tag"></span> Tags</a></li>
|
||||
<li><a href="{{ request.route_url('uploads') }}"><span class="glyphicon glyphicon-upload"></span> Téléchargements</a></li>
|
||||
<li><a href="{{ request.route_url('logout') }}"><span class="glyphicon glyphicon-off"></span> Se déconnecter</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% else %}
|
||||
<!-- si anonyme, lien pour se connecter -->
|
||||
<li><a href="{{ request.route_url('login') }}">
|
||||
<span class="glyphicon glyphicon-user"></span></a></li>
|
||||
{% endif %}
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
{% if request.path == '/' %}
|
||||
{# -- display carousel -- #}
|
||||
{% block carousel %}
|
||||
{% endblock carousel %}
|
||||
{% endif %}
|
||||
|
||||
<!-- Container (The Page Template Section) -->
|
||||
<div class="container">
|
||||
<!-- Display Page Title -->
|
||||
{% if page_title %}
|
||||
<h1>{{ page_title }}</h1>
|
||||
{% endif %}
|
||||
<br />
|
||||
<div id="messages">
|
||||
{% for queue in ['', 'info', 'success', 'warning', 'danger'] %}
|
||||
{% for message in request.session.pop_flash(queue) %}
|
||||
<div class="alert alert-{{queue}}">
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- display page content-->
|
||||
{% block content %}
|
||||
<p>No content</p>
|
||||
{% endblock content %}
|
||||
<br />
|
||||
<br />
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="text-center">
|
||||
<div class="row">
|
||||
<p class="text-center">
|
||||
© 2017 - Phuoc Cao
|
||||
 | <a href="{{ request.route_url('apropos')}}">A propos</a>
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Bootstrap core JavaScript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
||||
28
cao_osint/templates/login.jinja2
Normal file
28
cao_osint/templates/login.jinja2
Normal file
@@ -0,0 +1,28 @@
|
||||
{% extends "layout.jinja2" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-offset-4 col-md-5 well">
|
||||
|
||||
<form action="{{ login_url }}" method="post">
|
||||
<h2>Se connecter</h2>
|
||||
<div class="form-group">
|
||||
<input type="text" name="username" class="form-control" placeholder="Identifiant">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" name="password" class="form-control" placeholder="Mot de passe">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="submit" value="Se connecter" class="btn btn-primary">
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
|
||||
{% endblock %}
|
||||
55
cao_osint/templates/tag_edit.jinja2
Normal file
55
cao_osint/templates/tag_edit.jinja2
Normal file
@@ -0,0 +1,55 @@
|
||||
{% extends "cao_osint:templates/layout.jinja2" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form action="{{ url }}" method="post" class="form">
|
||||
|
||||
{% for error in form.tag.errors %}
|
||||
<div class="error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="tag">{{form.tag.label}}</label>
|
||||
{{form.tag(class_='form-control')}}
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<a class="btn btn-default" href="{{ request.route_url('tags') }}">
|
||||
<span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
|
||||
<button class="btn btn-primary" type="submit" name="form.submitted">
|
||||
<span class="glyphicon glyphicon-ok"></span> Enregistrer</button>
|
||||
{% if form.id.data %}
|
||||
<button class="btn btn-danger" type="button" data-toggle="modal" data-target="#confirmDelete">
|
||||
<span class="glyphicon glyphicon-remove"></span> Supprimer</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
<!-- Modal : Confirmation SUPRESSION -->
|
||||
<div id="confirmDelete" class="modal" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">Supprimer le Tag</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- The form is placed inside the body of modal -->
|
||||
<p>Etes-vous certain(e) de vouloir supprimer le Tag <b>{{ form.tag.data }}</b> ?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="form-group">
|
||||
<div class="text-center">
|
||||
<form id="confirmForm" method="post">
|
||||
<button type="submit" class="btn btn-danger" name="form.deleted">Supprimer</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
26
cao_osint/templates/tags.jinja2
Normal file
26
cao_osint/templates/tags.jinja2
Normal file
@@ -0,0 +1,26 @@
|
||||
{% extends "cao_osint:templates/layout.jinja2" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<p><a href="{{ request.route_url('tag_edit', id='0') }}" class="btn btn-success" role="button">
|
||||
<span class="glyphicon glyphicon-plus"></span> Nouveau</a>
|
||||
</p>
|
||||
|
||||
<table id="users_list" class="table table-striped table-bordered table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No Id</th>
|
||||
<th>Tag</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for entry in tags %}
|
||||
<tr>
|
||||
<td>{{ entry.id }}</td>
|
||||
<td>
|
||||
<a href="{{ request.route_url('tag_edit', id=entry.id) }}">{{ entry.tag }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
||||
52
cao_osint/templates/upload_edit.jinja2
Normal file
52
cao_osint/templates/upload_edit.jinja2
Normal file
@@ -0,0 +1,52 @@
|
||||
{% extends "layout.jinja2" %}
|
||||
|
||||
{% block content %}
|
||||
{% if message %}
|
||||
{{ message }}
|
||||
{% endif %}
|
||||
|
||||
|
||||
<form action="{{request.route_url('upload_edit', filename=filename)}}" method="post" class="form">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="new_name">Nouveau nom</label>
|
||||
<input type="text" name="new_name" class="form-control" value="{{ file }}">
|
||||
</div>
|
||||
<br>
|
||||
<div class="form-group">
|
||||
<a class="btn btn-default" href="{{ request.route_url('uploads') }}"><span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
|
||||
<button class="btn btn-primary" type="submit" name="form.submitted">
|
||||
<span class="glyphicon glyphicon-ok"></span> Renommer</button>
|
||||
<button class="btn btn-danger" type="button" data-toggle="modal" data-target="#confirmDelete">
|
||||
<span class="glyphicon glyphicon-remove"></span> Supprimer</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<!-- Modal : Confirmation SUPRESSION -->
|
||||
<div id="confirmDelete" class="modal" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">Supprimer un FICHIER</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- The form is placed inside the body of modal -->
|
||||
<p>Etes-vous certain(e) de vouloir supprimer ce fichier :<br>
|
||||
<b>{{ filename }}</b> ?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="form-group">
|
||||
<div class="text-center">
|
||||
<form id="confirmForm" method="post">
|
||||
<button type="submit" class="btn btn-danger" name="form.deleted">Supprimer</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
43
cao_osint/templates/uploads.jinja2
Normal file
43
cao_osint/templates/uploads.jinja2
Normal file
@@ -0,0 +1,43 @@
|
||||
{% extends "cao_osint:templates/layout.jinja2" %}
|
||||
{% block content %}
|
||||
|
||||
<div class="panel-group">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Ajouter un fichier</div>
|
||||
<div class="panel-body">
|
||||
<div class="col-sm-6">
|
||||
<form action="/uploads" method="post" accept-charset="utf-8" enctype="multipart/form-data">
|
||||
|
||||
<label for="uploadfile">Veuillez séléctionner un fichier</label>
|
||||
<input id="uploadfile" name="uploadfile" type="file" value="" />
|
||||
|
||||
<button class="btn btn-primary" type="submit" name="form.submitted">
|
||||
<span class="glyphicon glyphicon-ok"></span> Enregistrer</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-sm-6 well well-sm">
|
||||
<ul>
|
||||
<li>Seuls les documents au format <b>TXT, PDF, PNG, JPG ou JPEG</b> seront acceptés.</li>
|
||||
<li>La taille de chaque document ne doit <b>pas dépasser 4 Mo</b>.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Fichiers téléchargés</div>
|
||||
<div class="panel-body">
|
||||
<table id="uploads_list" class="table table-striped table-bordered table-condensed">
|
||||
{% for entry in files_list %}
|
||||
<tr>
|
||||
<td><a href="{{ entry[2] }}">{{ entry[0] }}</a></td>
|
||||
<td class="text-right">{{ entry[1] }}</td>
|
||||
<td class="text-center"><a href="{{request.route_url('upload_edit', filename=entry[0])}}">[ Modifier ]</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
55
cao_osint/templates/user_edit.jinja2
Normal file
55
cao_osint/templates/user_edit.jinja2
Normal file
@@ -0,0 +1,55 @@
|
||||
{% extends "cao_osint:templates/layout.jinja2" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if message %}
|
||||
<div class="alert alert-danger">
|
||||
{{ message }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<form action="{{ url }}" method="post" class="form">
|
||||
|
||||
{% for error in form.name.errors %}
|
||||
<div class="label label-warning">{{ error }}</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="name">{{form.name.label}}</label>
|
||||
{% if form.id.data %}
|
||||
<input class="form-control" name="name" readonly type="text" value="{{form.name.data}}">
|
||||
{% else %}
|
||||
{{form.name(class_='form-control')}}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="password">{{form.password.label}}</label>
|
||||
{{form.password(class_='form-control')}}
|
||||
</div>
|
||||
|
||||
{% for error in form.confirm.errors %}
|
||||
<div class="label label-danger">{{error}}</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class="form-group">
|
||||
<label class="required-field" for="confirm">{{form.confirm.label}}</label>
|
||||
{{form.confirm(class_='form-control')}}
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<div class="form-group">
|
||||
<a class="btn btn-default" href="{{ url_retour }}"><span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
|
||||
<button class="btn btn-primary" type="submit" name="form.submitted">
|
||||
<span class="glyphicon glyphicon-ok"></span> Enregistrer</button>
|
||||
{% if form.id.data and request.authenticated_userid == 'admin' %}
|
||||
<button class="btn btn-warning" type="submit" name="form.deleted">
|
||||
<span class="glyphicon glyphicon-remove"></span> Supprimer</button>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
32
cao_osint/templates/users.jinja2
Normal file
32
cao_osint/templates/users.jinja2
Normal file
@@ -0,0 +1,32 @@
|
||||
{% extends "layout.jinja2" %}
|
||||
|
||||
{% block content %}
|
||||
<p>
|
||||
<a href="{{ request.route_url('home' ) }}" class="btn btn-default" role="button">
|
||||
<span class="glyphicon glyphicon-chevron-left"></span> Retour</a>
|
||||
<a href="{{ request.route_url('user_edit', name='0') }}" class="btn btn-success" role="button">
|
||||
<span class="glyphicon glyphicon-plus"></span> Nouvel utilisateur</a>
|
||||
</p>
|
||||
|
||||
<table id="users_list" class="table table-striped table-bordered table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>No Id</th>
|
||||
<th>Nom</th>
|
||||
<th>Dernière connexion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for entry in users %}
|
||||
<tr>
|
||||
<td>{{ entry.id }}</td>
|
||||
<td>
|
||||
<a href="{{ request.route_url('user_edit', name=entry.name) }}">
|
||||
{{ entry.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td>{{ entry.last_logged.strftime("%d-%m-%Y - %H:%M") }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
||||
56
cao_osint/tests.py
Normal file
56
cao_osint/tests.py
Normal file
@@ -0,0 +1,56 @@
|
||||
import unittest
|
||||
|
||||
from pyramid import testing
|
||||
|
||||
import transaction
|
||||
|
||||
|
||||
def dummy_request(dbsession):
|
||||
return testing.DummyRequest(dbsession=dbsession)
|
||||
|
||||
|
||||
class BaseTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.config = testing.setUp(settings={
|
||||
'sqlalchemy.url': 'sqlite:///:memory:'
|
||||
})
|
||||
self.config.include('.models')
|
||||
settings = self.config.get_settings()
|
||||
|
||||
from .models import (
|
||||
get_engine,
|
||||
get_session_factory,
|
||||
get_tm_session,
|
||||
)
|
||||
|
||||
self.engine = get_engine(settings)
|
||||
session_factory = get_session_factory(self.engine)
|
||||
|
||||
self.session = get_tm_session(session_factory, transaction.manager)
|
||||
|
||||
def init_database(self):
|
||||
from .models.meta import Base
|
||||
Base.metadata.create_all(self.engine)
|
||||
|
||||
def tearDown(self):
|
||||
from .models.meta import Base
|
||||
|
||||
testing.tearDown()
|
||||
transaction.abort()
|
||||
Base.metadata.drop_all(self.engine)
|
||||
|
||||
|
||||
class TestMyViewSuccessCondition(BaseTest):
|
||||
|
||||
def test_passing_view(self):
|
||||
from .views.default import apropos
|
||||
response = apropos(dummy_request(self.session))
|
||||
self.assertEqual(response['page_title'], 'A propos')
|
||||
|
||||
|
||||
class TestMyViewFailureCondition(BaseTest):
|
||||
|
||||
def test_failing_view(self):
|
||||
from .views.default import apropos
|
||||
response = apropos(dummy_request(self.session))
|
||||
self.assertEqual(response['page_title'], 'A propos')
|
||||
0
cao_osint/views/__init__.py
Normal file
0
cao_osint/views/__init__.py
Normal file
160
cao_osint/views/blog.py
Normal file
160
cao_osint/views/blog.py
Normal file
@@ -0,0 +1,160 @@
|
||||
from pyramid.view import view_config
|
||||
from pyramid.httpexceptions import HTTPNotFound, HTTPFound
|
||||
from ..models.blog_record import BlogRecord, Tags
|
||||
from ..services.blog_record import BlogRecordService
|
||||
from ..forms import BlogCreateForm, BlogUpdateForm, BlogSearchForm, TagForm
|
||||
import markdown
|
||||
import datetime #<- will be used to set default dates on models
|
||||
|
||||
@view_config(route_name='blog',
|
||||
renderer='cao_osint:templates/blog.jinja2')
|
||||
def blog(request):
|
||||
# get post id from request
|
||||
blog_id = request.matchdict['id']
|
||||
entry = BlogRecordService.by_id(request, blog_id)
|
||||
|
||||
if not entry:
|
||||
request.session.flash(u"Page non trouvée : %s" % blog_id, 'warning')
|
||||
return HTTPFound(location=request.route_url('home'))
|
||||
|
||||
# insèrer le path de static/img
|
||||
body = entry.body.replace('static/', "%s/static/" % request.application_url)
|
||||
# convertir de markdown en HTML
|
||||
body_html = markdown.markdown(body, extensions=['footnotes'])
|
||||
|
||||
return {
|
||||
'page_title': entry.title,
|
||||
'entry': entry,
|
||||
'body_html': body_html,
|
||||
}
|
||||
|
||||
|
||||
@view_config(route_name='blog_edit', renderer='cao_osint:templates/blog_edit.jinja2', permission='view')
|
||||
def blog_edit(request):
|
||||
# get post id from request
|
||||
blog_id = request.matchdict['id']
|
||||
url = request.route_url('blog_edit',id=blog_id)
|
||||
|
||||
# get the list of tags
|
||||
tags = BlogRecordService.get_tags(request)
|
||||
|
||||
if blog_id == '0':
|
||||
# create a new post
|
||||
entry = BlogRecord()
|
||||
# set default values
|
||||
form = BlogCreateForm(request.POST, entry)
|
||||
form.tag.choices = [(row.tag, row.tag) for row in tags]
|
||||
page_title = 'Nouvelle page'
|
||||
else:
|
||||
# modify post
|
||||
entry = BlogRecordService.by_id(request, blog_id)
|
||||
if not entry:
|
||||
request.session.flash(u"Page non trouvée : %s" % blog_id, 'warning')
|
||||
return HTTPFound(location=request.route_url('home'))
|
||||
form = BlogUpdateForm(request.POST, entry)
|
||||
form.tag.choices = [(row.tag, row.tag) for row in tags]
|
||||
page_title = 'Modifier : ' + entry.title
|
||||
|
||||
if 'form.submitted' in request.params and form.validate():
|
||||
if blog_id == '0':
|
||||
form.populate_obj(entry)
|
||||
# interdire le car '/' dans le titre à cause du slug
|
||||
entry.title = entry.title.replace('/','.')
|
||||
entry.creator = request.authenticated_userid
|
||||
entry.editor = entry.creator
|
||||
request.dbsession.add(entry)
|
||||
|
||||
return HTTPFound(location=request.route_url('home'))
|
||||
else:
|
||||
del form.id # SECURITY: prevent overwriting of primary key
|
||||
form.populate_obj(entry)
|
||||
# interdire le car '/' dans le titre à cause du slug
|
||||
entry.title = entry.title.replace('/','.')
|
||||
entry.edited = datetime.datetime.now()
|
||||
entry.editor = request.authenticated_userid
|
||||
return HTTPFound(location=request.route_url('blog', id=entry.id, slug=entry.slug))
|
||||
|
||||
if 'form.deleted' in request.params:
|
||||
BlogRecordService.delete(request, blog_id)
|
||||
request.session.flash("La page a été supprimée avec succès.", 'success')
|
||||
return HTTPFound(location=request.route_url('home'))
|
||||
|
||||
return {
|
||||
'page_title': page_title,
|
||||
'url': url,
|
||||
'form': form,
|
||||
'blog_id': blog_id,
|
||||
'entry': entry, }
|
||||
|
||||
|
||||
@view_config(route_name='blog_search',
|
||||
renderer='cao_osint:templates/blog_search.jinja2')
|
||||
def blog_search(request):
|
||||
|
||||
criteria = ''
|
||||
items = []
|
||||
form = BlogSearchForm(request.POST)
|
||||
if 'form.submitted' in request.params and form.validate():
|
||||
criteria = request.params['criteria']
|
||||
# si afficher tous les fiches ?
|
||||
items = BlogRecordService.by_criteria(request, criteria)
|
||||
|
||||
return {
|
||||
'page_title': "Rechercher",
|
||||
'form': form,
|
||||
'items': items,
|
||||
'criteria': criteria,
|
||||
}
|
||||
|
||||
@view_config(route_name='tags', renderer='cao_osint:templates/tags.jinja2', permission='view')
|
||||
def tags(request):
|
||||
|
||||
# get the list of tags of this topic
|
||||
tags = BlogRecordService.get_tags(request)
|
||||
|
||||
return {
|
||||
'page_title': 'Tags',
|
||||
'tags': tags,
|
||||
}
|
||||
|
||||
@view_config(route_name='tag_edit', renderer='cao_osint:templates/tag_edit.jinja2', permission='view')
|
||||
def tag_edit(request):
|
||||
# get tag parameters from request
|
||||
tag_id = request.matchdict['id']
|
||||
url = request.route_url('tag_edit', id=tag_id)
|
||||
|
||||
if tag_id == '0':
|
||||
# create a new tag
|
||||
entry = Tags()
|
||||
form = TagForm(request.POST, entry)
|
||||
page_title = "Nouveau Tag"
|
||||
|
||||
else:
|
||||
# modify post
|
||||
entry = BlogRecordService.get_tags_byId(request, tag_id)
|
||||
if not entry:
|
||||
request.session.flash(u"Tag non trouvé : %s" % tag_id, 'warning')
|
||||
return HTTPFound(location=request.route_url('tags'))
|
||||
form = TagForm(request.POST, entry)
|
||||
page_title = entry.tag
|
||||
|
||||
if 'form.submitted' in request.params and form.validate():
|
||||
if tag_id == '0':
|
||||
form.populate_obj(entry)
|
||||
request.dbsession.add(entry)
|
||||
return HTTPFound(location=request.route_url('tags'))
|
||||
else:
|
||||
del form.id # SECURITY: prevent overwriting of primary key
|
||||
form.populate_obj(entry)
|
||||
return HTTPFound(location=request.route_url('tags'))
|
||||
|
||||
if 'form.deleted' in request.params:
|
||||
BlogRecordService.tag_delete(request, entry.id)
|
||||
request.session.flash("La fiche a été supprimée avec succès.", 'success')
|
||||
return HTTPFound(location=request.route_url('tags'))
|
||||
|
||||
return {
|
||||
'page_title': page_title,
|
||||
'url': url,
|
||||
'form': form,
|
||||
}
|
||||
245
cao_osint/views/default.py
Normal file
245
cao_osint/views/default.py
Normal file
@@ -0,0 +1,245 @@
|
||||
from pyramid.view import (
|
||||
view_config,
|
||||
forbidden_view_config,
|
||||
)
|
||||
from pyramid.httpexceptions import HTTPFound
|
||||
from pyramid.security import remember, forget
|
||||
from ..services.user import UserService
|
||||
from ..services.blog_record import BlogRecordService
|
||||
from ..forms import UserCreateForm, BlogSearchForm
|
||||
from ..models.user import User
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import magic
|
||||
|
||||
@view_config(route_name='home',
|
||||
renderer='cao_osint:templates/home.jinja2')
|
||||
def home(request):
|
||||
# get the last created posts
|
||||
last_ten = BlogRecordService.get_last_created(request)
|
||||
|
||||
criteria = ''
|
||||
form = BlogSearchForm(request.POST)
|
||||
|
||||
return {
|
||||
'page_title': "Bienvenue sur mon blog",
|
||||
'last_ten': last_ten,
|
||||
'form': form,
|
||||
'criteria': criteria,
|
||||
}
|
||||
|
||||
|
||||
@view_config(route_name='apropos',
|
||||
renderer='cao_osint:templates/apropos.jinja2')
|
||||
def apropos(request):
|
||||
|
||||
return {
|
||||
'page_title': "A propos",
|
||||
}
|
||||
|
||||
|
||||
@view_config(route_name='login', renderer='cao_osint:templates/login.jinja2')
|
||||
@forbidden_view_config(renderer='cao_osint:templates/login.jinja2')
|
||||
def login(request):
|
||||
username = ''
|
||||
login_url = request.route_url('login')
|
||||
|
||||
referrer = request.url
|
||||
if referrer == login_url:
|
||||
referrer = '/' # never use the login form itself as came_from
|
||||
|
||||
came_from = request.params.get('came_from', referrer)
|
||||
username = request.POST.get('username')
|
||||
userpwd = request.POST.get('password')
|
||||
if username:
|
||||
user = UserService.by_name(request, username)
|
||||
if user and user.verify_password(userpwd):
|
||||
headers = remember(request, username)
|
||||
request.session.flash("Bienvenue %s !" % username, 'success')
|
||||
return HTTPFound(location=came_from, headers=headers)
|
||||
else:
|
||||
headers = forget(request)
|
||||
request.session.flash("Login et mot de passe invalides. La connexion a échoué.", "danger")
|
||||
|
||||
return {
|
||||
'page_title': "",
|
||||
'came_from': came_from,
|
||||
'login_url': login_url,
|
||||
}
|
||||
|
||||
|
||||
@view_config(route_name='logout', renderer='string')
|
||||
def logout(request):
|
||||
username = request.authenticated_userid
|
||||
headers = forget(request)
|
||||
request.session.flash('Au revoir ' + username + ' !', 'success')
|
||||
return HTTPFound(location=request.route_url('home'), headers=headers)
|
||||
|
||||
|
||||
@view_config(route_name='users', renderer='cao_osint:templates/users.jinja2', permission='manage')
|
||||
def users(request):
|
||||
# get all users
|
||||
users = UserService.all(request)
|
||||
return {
|
||||
'page_title': "Liste des utilisateurs",
|
||||
'users': users
|
||||
}
|
||||
|
||||
|
||||
@view_config(route_name='user_edit', renderer='cao_osint:templates/user_edit.jinja2', permission='view')
|
||||
def user_edit(request):
|
||||
message = ''
|
||||
name = request.matchdict['name']
|
||||
url = request.route_url('user_edit', name=name)
|
||||
if request.authenticated_userid == 'admin':
|
||||
url_retour = request.route_url('users')
|
||||
else:
|
||||
url_retour = request.route_url('home')
|
||||
|
||||
if name == '0':
|
||||
# nouvel utilisateur
|
||||
user = User()
|
||||
form = UserCreateForm(request.POST, user)
|
||||
page_title = "Nouvel utilisateur"
|
||||
else:
|
||||
# lire la fiche du user
|
||||
user = UserService.by_name(request, name)
|
||||
if not user:
|
||||
request.session.flash("Utilisateur non trouvé : %s" % name, 'danger')
|
||||
return HTTPFound(location=url_retour)
|
||||
|
||||
form = UserCreateForm(request.POST, user)
|
||||
page_title = "Modification utilisateur"
|
||||
|
||||
|
||||
if 'form.submitted' in request.params and form.validate():
|
||||
# controle que le password a moins 6 car
|
||||
if len(form.password.data) < 6 :
|
||||
message = "Le mot de passe doit avoir au moins 6 caractères"
|
||||
else:
|
||||
if name == '0':
|
||||
# en création, controler que le nouvel user n'existe pas dans la BD
|
||||
new_user = UserService.by_name(request, form.name.data)
|
||||
if new_user:
|
||||
message = "Utilisateur déjà créé : %s" % form.name.data
|
||||
else:
|
||||
form.populate_obj(user)
|
||||
user.set_password(form.password.data.encode('utf8'))
|
||||
# créer le nouveau
|
||||
request.dbsession.add(user)
|
||||
request.session.flash("La fiche a été créée avec succès.", 'success')
|
||||
return HTTPFound(location=url_retour)
|
||||
|
||||
else:
|
||||
# en modif
|
||||
del form.name # SECURITY: prevent overwriting of primary key
|
||||
form.populate_obj(user)
|
||||
user.set_password(form.password.data.encode('utf8'))
|
||||
request.session.flash("La fiche a été modifiée avec succès.", 'success')
|
||||
return HTTPFound(location=url_retour)
|
||||
|
||||
if 'form.deleted' in request.params:
|
||||
UserService.delete(request, user.id)
|
||||
request.session.flash("La fiche a été supprimée avec succès.", 'success')
|
||||
return HTTPFound(location=url_retour)
|
||||
|
||||
return {
|
||||
'page_title': page_title,
|
||||
'message': message,
|
||||
'form': form,
|
||||
'url': url,
|
||||
'url_retour': url_retour,
|
||||
'name': name,
|
||||
}
|
||||
|
||||
|
||||
@view_config(route_name='uploads', renderer='cao_osint:templates/uploads.jinja2', permission='view')
|
||||
def uploads(request):
|
||||
message = ''
|
||||
folder_path = request.registry.settings['uploads_dir']
|
||||
|
||||
files_list = []
|
||||
# récupérer tous les fichiers contenus dans dossier static/uploads
|
||||
for f in os.scandir(folder_path):
|
||||
file = []
|
||||
file_url = request.static_url('cao_osint:static/uploads/') + f.name
|
||||
file_path = folder_path + f.name
|
||||
file.append(f.name)
|
||||
file.append('%s Ko' % round(os.path.getsize(file_path) / 1024))
|
||||
file.append(file_url)
|
||||
files_list.append(file)
|
||||
|
||||
|
||||
if 'form.submitted' in request.params:
|
||||
# controler que le nom du fichier n'est pas vide
|
||||
if request.POST['uploadfile'] != b'':
|
||||
# récupère le fichier download dans le dossier /tmp
|
||||
input_file = request.POST['uploadfile'].file
|
||||
input_name = request.POST['uploadfile'].filename
|
||||
ext_allowed = ['text/plain', 'application/pdf', 'image/jpeg', 'image/jpg', 'image/png']
|
||||
|
||||
mime = magic.from_buffer(input_file.read(), mime=True)
|
||||
import pdb;pdb.set_trace()
|
||||
# types de fichiers autorisés ?
|
||||
if mime not in ext_allowed:
|
||||
request.session.flash("ERREUR: Le format du fichier n'est pas valide. Téléchargement impossible.", 'danger')
|
||||
return HTTPFound(location=request.route_url('uploads'))
|
||||
|
||||
# Finally write the data to a temporary file
|
||||
temp_file_path = os.path.join(folder_path, input_name)
|
||||
# supprimer le fichier s'il existe déjà
|
||||
if os.path.exists(temp_file_path):
|
||||
os.remove(temp_file_path)
|
||||
|
||||
# copie le fichier upload dans temp_file
|
||||
input_file.seek(0)
|
||||
with open(temp_file_path, 'wb') as output_file:
|
||||
shutil.copyfileobj(input_file, output_file)
|
||||
|
||||
# controler la taille du fichier < 4 Mo
|
||||
filesize = round(os.path.getsize(temp_file_path) / 1024)
|
||||
if filesize > 4096:
|
||||
os.remove(temp_file_path)
|
||||
request.session.flash("ERREUR: La taille du fichier dépasse la limite autorisée. Téléchargement impossible.", 'danger')
|
||||
return HTTPFound(location=request.route_url('uploads'))
|
||||
|
||||
request.session.flash('%s : Ce fichier est téléchargé avec succès.' % input_name, 'success')
|
||||
return HTTPFound(location=request.route_url('uploads'))
|
||||
|
||||
|
||||
return {
|
||||
'page_title': "Téléchargements",
|
||||
'files_list': files_list
|
||||
}
|
||||
|
||||
|
||||
@view_config(route_name='upload_edit', renderer='cao_osint:templates/upload_edit.jinja2')
|
||||
def upload_edit(request):
|
||||
filename = request.matchdict['filename']
|
||||
|
||||
message = ''
|
||||
folder_path = request.registry.settings['uploads_dir']
|
||||
|
||||
if 'form.submitted' in request.params:
|
||||
new_name = request.params["new_name"].lower()
|
||||
ext = new_name[-3:]
|
||||
# comparer le nouveau ext avec l'ancien
|
||||
if ext == filename[-3:]:
|
||||
os.rename(folder_path + filename, folder_path + new_name)
|
||||
return HTTPFound(location=request.route_url('uploads'))
|
||||
else:
|
||||
message = "Extension de fichier invalide !"
|
||||
|
||||
if 'form.deleted' in request.params:
|
||||
os.remove(folder_path + filename)
|
||||
request.session.flash("Le fichier a été supprimé avec succès.", 'success')
|
||||
return HTTPFound(location=request.route_url('uploads'))
|
||||
|
||||
return {
|
||||
'page_title': "Modifier : " + filename,
|
||||
'message': message,
|
||||
'filename': filename,
|
||||
'file_url': request.static_url('cao_osint:static/uploads/') + filename,
|
||||
}
|
||||
|
||||
7
cao_osint/views/notfound.py
Normal file
7
cao_osint/views/notfound.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from pyramid.view import notfound_view_config
|
||||
|
||||
|
||||
@notfound_view_config(renderer='../templates/404.jinja2')
|
||||
def notfound_view(request):
|
||||
request.response.status = 404
|
||||
return {}
|
||||
83
development.ini
Normal file
83
development.ini
Normal file
@@ -0,0 +1,83 @@
|
||||
###
|
||||
# app configuration
|
||||
# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
|
||||
###
|
||||
|
||||
[app:main]
|
||||
use = egg:cao_osint
|
||||
|
||||
pyramid.reload_templates = true
|
||||
pyramid.debug_authorization = false
|
||||
pyramid.debug_notfound = false
|
||||
pyramid.debug_routematch = false
|
||||
pyramid.default_locale_name = en
|
||||
pyramid.includes =
|
||||
pyramid_debugtoolbar
|
||||
|
||||
sqlalchemy.url = sqlite:///%(here)s/cao_osint.sqlite
|
||||
|
||||
# upload files location
|
||||
uploads_dir = /pyramid/cao_osint/cao_osint/static/uploads/
|
||||
|
||||
retry.attempts = 3
|
||||
|
||||
# By default, the toolbar only appears for clients from IP addresses
|
||||
# '127.0.0.1' and '::1'.
|
||||
# debugtoolbar.hosts = 127.0.0.1 ::1
|
||||
|
||||
[pshell]
|
||||
setup = cao_osint.pshell.setup
|
||||
|
||||
###
|
||||
# wsgi server configuration
|
||||
###
|
||||
|
||||
[alembic]
|
||||
# path to migration scripts
|
||||
script_location = cao_osint/alembic
|
||||
file_template = %%(year)d%%(month).2d%%(day).2d_%%(rev)s
|
||||
# file_template = %%(rev)s_%%(slug)s
|
||||
|
||||
[server:main]
|
||||
use = egg:waitress#main
|
||||
listen = localhost:6543
|
||||
|
||||
###
|
||||
# logging configuration
|
||||
# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
|
||||
###
|
||||
|
||||
[loggers]
|
||||
keys = root, cao_osint, sqlalchemy
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
[logger_root]
|
||||
level = INFO
|
||||
handlers = console
|
||||
|
||||
[logger_cao_osint]
|
||||
level = DEBUG
|
||||
handlers =
|
||||
qualname = cao_osint
|
||||
|
||||
[logger_sqlalchemy]
|
||||
level = WARN
|
||||
handlers =
|
||||
qualname = sqlalchemy.engine
|
||||
# "level = INFO" logs SQL queries.
|
||||
# "level = DEBUG" logs SQL queries and results.
|
||||
# "level = WARN" logs neither. (Recommended for production systems.)
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
[formatter_generic]
|
||||
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
|
||||
76
production.ini
Normal file
76
production.ini
Normal file
@@ -0,0 +1,76 @@
|
||||
###
|
||||
# app configuration
|
||||
# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
|
||||
###
|
||||
|
||||
[app:main]
|
||||
use = egg:cao_osint
|
||||
|
||||
pyramid.reload_templates = false
|
||||
pyramid.debug_authorization = false
|
||||
pyramid.debug_notfound = false
|
||||
pyramid.debug_routematch = false
|
||||
pyramid.default_locale_name = en
|
||||
|
||||
sqlalchemy.url = sqlite:///%(here)s/cao_osint.sqlite
|
||||
# upload files location
|
||||
uploads_dir = /pyramid/cao_osint/cao_osint/static/uploads/
|
||||
|
||||
retry.attempts = 3
|
||||
|
||||
[pshell]
|
||||
setup = cao_osint.pshell.setup
|
||||
|
||||
###
|
||||
# wsgi server configuration
|
||||
###
|
||||
|
||||
[alembic]
|
||||
# path to migration scripts
|
||||
script_location = cao_osint/alembic
|
||||
file_template = %%(year)d%%(month).2d%%(day).2d_%%(rev)s
|
||||
# file_template = %%(rev)s_%%(slug)s
|
||||
|
||||
[server:main]
|
||||
use = egg:waitress#main
|
||||
listen = *:6543
|
||||
|
||||
###
|
||||
# logging configuration
|
||||
# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
|
||||
###
|
||||
|
||||
[loggers]
|
||||
keys = root, cao_osint, sqlalchemy
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
[logger_root]
|
||||
level = WARN
|
||||
handlers = console
|
||||
|
||||
[logger_cao_osint]
|
||||
level = WARN
|
||||
handlers =
|
||||
qualname = cao_osint
|
||||
|
||||
[logger_sqlalchemy]
|
||||
level = WARN
|
||||
handlers =
|
||||
qualname = sqlalchemy.engine
|
||||
# "level = INFO" logs SQL queries.
|
||||
# "level = DEBUG" logs SQL queries and results.
|
||||
# "level = WARN" logs neither. (Recommended for production systems.)
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
[formatter_generic]
|
||||
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
|
||||
3
pytest.ini
Normal file
3
pytest.ini
Normal file
@@ -0,0 +1,3 @@
|
||||
[pytest]
|
||||
testpaths = cao_osint
|
||||
python_files = test*.py
|
||||
67
setup.py
Normal file
67
setup.py
Normal file
@@ -0,0 +1,67 @@
|
||||
import os
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
with open(os.path.join(here, 'README.md')) as f:
|
||||
README = f.read()
|
||||
with open(os.path.join(here, 'CHANGES.txt')) as f:
|
||||
CHANGES = f.read()
|
||||
|
||||
requires = [
|
||||
'plaster_pastedeploy',
|
||||
'pyramid',
|
||||
'pyramid_jinja2',
|
||||
'pyramid_debugtoolbar',
|
||||
'waitress',
|
||||
'alembic',
|
||||
'pyramid_retry',
|
||||
'pyramid_layout',
|
||||
'pyramid_tm',
|
||||
'python-magic',
|
||||
'SQLAlchemy',
|
||||
'transaction',
|
||||
'zope.sqlalchemy',
|
||||
'wtforms', # form library 2.2.1
|
||||
'webhelpers2', # various web building related helpers 2.0
|
||||
'passlib',
|
||||
'markdown',
|
||||
]
|
||||
|
||||
tests_require = [
|
||||
'WebTest >= 1.3.1', # py3 compat
|
||||
'pytest >= 3.7.4',
|
||||
'pytest-cov',
|
||||
]
|
||||
|
||||
setup(
|
||||
name='cao_osint',
|
||||
version='1.0',
|
||||
description='cao_osint',
|
||||
long_description=README + '\n\n' + CHANGES,
|
||||
classifiers=[
|
||||
'Programming Language :: Python',
|
||||
'Framework :: Pyramid',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Internet :: WWW/HTTP :: WSGI :: Application',
|
||||
],
|
||||
author='',
|
||||
author_email='',
|
||||
url='',
|
||||
keywords='web pyramid pylons',
|
||||
packages=find_packages(),
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
extras_require={
|
||||
'testing': tests_require,
|
||||
},
|
||||
install_requires=requires,
|
||||
entry_points={
|
||||
'paste.app_factory': [
|
||||
'main = cao_osint:main',
|
||||
],
|
||||
'console_scripts': [
|
||||
'initialize_cao_osint_db=cao_osint.scripts.initialize_db:main',
|
||||
],
|
||||
},
|
||||
)
|
||||
Reference in New Issue
Block a user