| 1 |  |  | # -*- coding: utf-8 -*- | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  | from sqlalchemy.orm import Session | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | from sqlalchemy import inspect | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  | from sqlalchemy.orm.unitofwork import UOWTransaction | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | from transaction import TransactionManager | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | from contextlib import contextmanager | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  | from tracim_backend.exceptions import ContentRevisionDeleteError | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  | from tracim_backend.exceptions import ContentRevisionUpdateError | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  | from tracim_backend.exceptions import SameValueError | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  | from tracim_backend.models.data import ContentRevisionRO | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  | from tracim_backend.models.data import Content | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  | from tracim_backend.models.meta import DeclarativeBase | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |  | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 16 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 17 |  |  | def prevent_content_revision_delete( | 
            
                                                                        
                            
            
                                    
            
            
                | 18 |  |  |         session: Session, | 
            
                                                                        
                            
            
                                    
            
            
                | 19 |  |  |         flush_context: UOWTransaction, | 
            
                                                                        
                            
            
                                    
            
            
                | 20 |  |  |         instances: [DeclarativeBase] | 
            
                                                                        
                            
            
                                    
            
            
                | 21 |  |  | ) -> None: | 
            
                                                                        
                            
            
                                    
            
            
                | 22 |  |  |     for instance in session.deleted: | 
            
                                                                        
                            
            
                                    
            
            
                | 23 |  |  |         if isinstance(instance, ContentRevisionRO) \ | 
            
                                                                        
                            
            
                                    
            
            
                | 24 |  |  |                 and instance.revision_id is not None: | 
            
                                                                        
                            
            
                                    
            
            
                | 25 |  |  |             raise ContentRevisionDeleteError( | 
            
                                                                        
                            
            
                                    
            
            
                | 26 |  |  |                 "ContentRevision is not deletable. " + | 
            
                                                                        
                            
            
                                    
            
            
                | 27 |  |  |                 "You must make a new revision with" + | 
            
                                                                        
                            
            
                                    
            
            
                | 28 |  |  |                 "is_deleted set to True. Look at " + | 
            
                                                                        
                            
            
                                    
            
            
                | 29 |  |  |                 "tracim.model.new_revision context " + | 
            
                                                                        
                            
            
                                    
            
            
                | 30 |  |  |                 "manager to make a new revision" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |             ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  | class RevisionsIntegrity(object): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |     Simple static used class to manage a list with list of ContentRevisionRO | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |     who are allowed to be updated. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |     When modify an already existing (understood have an identity in databse) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |     ContentRevisionRO, if it's not in RevisionsIntegrity._updatable_revisions | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |     list, a ContentRevisionUpdateError thrown. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |     This class is used by tracim.model.new_revision context manager. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |     _updatable_revisions = [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |     def add_to_updatable(cls, revision: 'ContentRevisionRO') -> None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |         if inspect(revision).has_identity: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |             raise ContentRevisionUpdateError("ContentRevision is not updatable. %s already have identity." % revision)  # nopep8 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |         if revision not in cls._updatable_revisions: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |             cls._updatable_revisions.append(revision) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |     def remove_from_updatable(cls, revision: 'ContentRevisionRO') -> None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |         if revision in cls._updatable_revisions: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |             cls._updatable_revisions.remove(revision) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |     def is_updatable(cls, revision: 'ContentRevisionRO') -> bool: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |         return revision in cls._updatable_revisions | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  | @contextmanager | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  | def new_revision( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |         session: Session, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |         tm: TransactionManager, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |         content: Content, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |         force_create_new_revision: bool=False, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  | ) -> Content: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |     Prepare context to update a Content. It will add a new updatable revision | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |     to the content. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |     :param session: Database _session | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |     :param tm: TransactionManager | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |     :param content: Content instance to update | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |     :param force_create_new_revision: Decide if new_rev should or should not | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |     be forced. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |     :return: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |     """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |     with session.no_autoflush: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |         try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |             if force_create_new_revision \ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |                     or inspect(content.revision).has_identity: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |                 content.new_revision() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |             RevisionsIntegrity.add_to_updatable(content.revision) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |             yield content | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |         except Exception as e: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  |             # INFO - GM - 14-11-2018 - rollback session and renew | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |             # transaction when error happened | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |             # This avoid bad _session data like new "temporary" revision | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |             # to be add when problem happen. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |             session.rollback() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |             tm.abort() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |             tm.begin() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |             raise e | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |         finally: | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 99 |  |  |             RevisionsIntegrity.remove_from_updatable(content.revision) | 
            
                                                        
            
                                    
            
            
                | 100 |  |  |  |