Exemple #1
0
    def test_delete_with_plugins(self):
        """
        Check that plugins and placeholders get correctly deleted when we delete
        a page!
        """
        home = create_page("home", "nav_playground.html", "en")
        page = create_page("page", "nav_playground.html", "en")
        page.rescan_placeholders() # create placeholders
        placeholder = page.placeholders.all()[0]
        plugin_base = CMSPlugin(
            plugin_type='TextPlugin',
            placeholder=placeholder,
            position=1,
            language=settings.LANGUAGES[0][0]
        )
        plugin_base.insert_at(None, position='last-child', save=False)

        plugin = Text(body='')
        plugin_base.set_base_attr(plugin)
        plugin.save()
        self.assertEqual(CMSPlugin.objects.count(), 1)
        self.assertEqual(Text.objects.count(), 1)
        self.assertTrue(Placeholder.objects.count() > 2)
        page.delete()
        home.delete()
        self.assertEqual(CMSPlugin.objects.count(), 0)
        self.assertEqual(Text.objects.count(), 0)
        self.assertEqual(Placeholder.objects.count(), 0)
        self.assertEqual(Page.objects.count(), 0)
Exemple #2
0
    def test_delete_with_plugins(self):
        """
        Check that plugins and placeholders get correctly deleted when we delete
        a page!
        """
        page = create_page("page", "nav_playground.html", "en")
        page.rescan_placeholders() # create placeholders
        placeholder = page.placeholders.all()[0]
        plugin_base = CMSPlugin(
            plugin_type='TextPlugin',
            placeholder=placeholder,
            position=1,
            language=settings.LANGUAGES[0][0]
        )
        plugin_base.insert_at(None, position='last-child', save=False)

        plugin = Text(body='')
        plugin_base.set_base_attr(plugin)
        plugin.save()
        self.assertEqual(CMSPlugin.objects.count(), 1)
        self.assertEqual(Text.objects.count(), 1)
        self.assertTrue(Placeholder.objects.count() > 0)
        page.delete()
        self.assertEqual(CMSPlugin.objects.count(), 0)
        self.assertEqual(Text.objects.count(), 0)
        self.assertEqual(Placeholder.objects.count(), 0)
Exemple #3
0
def add_plugin(placeholder, plugin_type, language, position='last-child',
               target=None, **data):
    """
    Add a plugin to a placeholder
    
    See docs/extending_cms/api_reference.rst for more info
    """
    # validate placeholder
    assert isinstance(placeholder, Placeholder)
    
    # validate and normalize plugin type
    plugin_model, plugin_type = _verify_plugin_type(plugin_type)
        

    max_pos = CMSPlugin.objects.filter(language=language,
        placeholder=placeholder).aggregate(Max('position'))['position__max'] or 0

    plugin_base = CMSPlugin(
        plugin_type=plugin_type,
        placeholder=placeholder, 
        position=max_pos + 1,
        language=language
    )
    plugin_base.insert_at(target, position=position, save=False)
            
    plugin = plugin_model(**data)
    plugin_base.set_base_attr(plugin)
    plugin.save()
    return plugin
Exemple #4
0
    def add_plugin(self,
                   user=None,
                   page=None,
                   placeholder=None,
                   language='en',
                   body=''):
        if not placeholder:
            if page:
                placeholder = page.placeholders.get(
                    slot__iexact='Right-Column')
            else:
                placeholder = page.placeholders.get(
                    slot__iexact='Right-Column')

        plugin_base = CMSPlugin(
            plugin_type='TextPlugin',
            placeholder=placeholder,
            position=1,
            language=language)
        plugin_base.insert_at(None, position='last-child', commit=False)

        plugin = Text(body=body)
        plugin_base.set_base_attr(plugin)
        plugin.save()
        return plugin.pk
Exemple #5
0
def add_plugin(placeholder,
               plugin_type,
               language,
               position='last-child',
               target=None,
               **data):
    """
    Add a plugin to a placeholder
    
    See docs/extending_cms/api_reference.rst for more info
    """
    # validate placeholder
    assert isinstance(placeholder, Placeholder)

    # validate and normalize plugin type
    plugin_model, plugin_type = _verify_plugin_type(plugin_type)

    max_pos = CMSPlugin.objects.filter(
        language=language, placeholder=placeholder).aggregate(
            Max('position'))['position__max'] or 0

    plugin_base = CMSPlugin(plugin_type=plugin_type,
                            placeholder=placeholder,
                            position=max_pos + 1,
                            language=language)
    plugin_base.insert_at(target, position=position, save=False)

    plugin = plugin_model(**data)
    plugin_base.set_base_attr(plugin)
    plugin.save()
    return plugin
Exemple #6
0
def add_plugin(placeholder, plugin_type, language, position='last-child',
               **data):
    """
    Add a plugin to a placeholder
    
    See docs/extending_cms/api_reference.rst for more info
    """
    # validate placeholder
    assert isinstance(placeholder, Placeholder)
    
    # validate and normalize plugin type
    plugin_model, plugin_type = _verify_plugin_type(plugin_type)
        
    plugin_base = CMSPlugin(
        plugin_type=plugin_type,
        placeholder=placeholder, 
        position=1, 
        language=language
    )
    plugin_base.insert_at(None, position=position, save=False)
            
    plugin = plugin_model(**data)
    plugin_base.set_base_attr(plugin)
    plugin.save()
    return plugin
Exemple #7
0
    def test_delete_with_plugins(self):
        """
        Check that plugins and placeholders get correctly deleted when we delete
        a page!
        """
        Text = self.get_plugin_model('TextPlugin')
        home = create_page("home", "nav_playground.html", "en")
        page = create_page("page", "nav_playground.html", "en")
        page.rescan_placeholders() # create placeholders
        placeholder = page.placeholders.all()[0]
        plugin_base = CMSPlugin(
            plugin_type='TextPlugin',
            placeholder=placeholder,
            position=1,
            language=settings.LANGUAGES[0][0]
        )
        plugin_base = plugin_base.add_root(instance=plugin_base)

        plugin = Text(body='')
        plugin_base.set_base_attr(plugin)
        plugin.save()
        self.assertEqual(CMSPlugin.objects.count(), 1)
        self.assertEqual(Text.objects.count(), 1)
        self.assertTrue(Placeholder.objects.count() > 2)
        page.delete()
        home.delete()
        self.assertEqual(CMSPlugin.objects.count(), 0)
        self.assertEqual(Text.objects.count(), 0)
        self.assertEqual(Placeholder.objects.count(), 0)
        self.assertEqual(Page.objects.count(), 0)
Exemple #8
0
def add_plugin(placeholder,
               plugin_type,
               language,
               position='last-child',
               target=None,
               **data):
    """
    Add a plugin to a placeholder
    
    See docs/extending_cms/api_reference.rst for more info
    """
    # validate placeholder
    assert isinstance(placeholder, Placeholder)

    # validate and normalize plugin type
    plugin_model, plugin_type = _verify_plugin_type(plugin_type)
    if target:
        if position == 'last-child':
            new_pos = CMSPlugin.objects.filter(language=language,
                                               parent=target,
                                               tree_id=target.tree_id).count()
        elif position == 'first-child':
            new_pos = 0
        elif position == 'left':
            new_pos = target.position
        elif position == 'right':
            new_pos = target.position + 1
        else:
            raise Exception('position not supported: %s' % position)
        for pl in CMSPlugin.objects.filter(language=language,
                                           parent=target.parent_id,
                                           tree_id=target.tree_id,
                                           position__gte=new_pos):
            pl.position += 1
            pl.save()
    else:
        new_pos = CMSPlugin.objects.filter(language=language,
                                           parent__isnull=True,
                                           placeholder=placeholder).count()

    plugin_base = CMSPlugin(plugin_type=plugin_type,
                            placeholder=placeholder,
                            position=new_pos,
                            language=language)
    plugin_base.insert_at(target, position=position, save=False)

    plugin = plugin_model(**data)
    plugin_base.set_base_attr(plugin)
    plugin.save()
    return plugin
Exemple #9
0
def add_plugin(placeholder, plugin_type, language, position='last-child', **data):
    """
    Taken from django-cms api (in newer versions)
    https://github.com/divio/django-cms/blob/b8633b42efcd137d96e1e3f42e004cb7595768fe/cms/api.py
    """
    assert isinstance(placeholder, Placeholder)
    plugin_model = plugin_type.model
    plugin_type = plugin_type.__name__
    plugin_base = CMSPlugin(
        plugin_type=plugin_type,
        placeholder=placeholder, 
        position=1,
        language=language
    )
    plugin_base.insert_at(None, position='last-child', commit=False)
    plugin = plugin_model(**data)
    plugin_base.set_base_attr(plugin)
    plugin.save()
    return plugin
Exemple #10
0
 def add_plugin(self, user=None, page=None, placeholder=None, language='en', body=''):
     if not placeholder:
         if page:
             placeholder = page.placeholders.get(slot__iexact='Right-Column')
         else:
             placeholder = page.placeholders.get(slot__iexact='Right-Column')
         
     plugin_base = CMSPlugin(
         plugin_type='TextPlugin',
         placeholder=placeholder, 
         position=1, 
         language=language
     )
     plugin_base.insert_at(None, position='last-child', commit=False)
             
     plugin = Text(body=body)
     plugin_base.set_base_attr(plugin)
     plugin.save()
     return plugin.pk
Exemple #11
0
def add_plugin(placeholder, plugin_type, language, position='last-child',
               target=None, **data):
    """
    Add a plugin to a placeholder
    
    See docs/extending_cms/api_reference.rst for more info
    """
    # validate placeholder
    assert isinstance(placeholder, Placeholder)

    # validate and normalize plugin type
    plugin_model, plugin_type = _verify_plugin_type(plugin_type)
    if target:
        if position == 'last-child':
            new_pos = CMSPlugin.objects.filter(language=language, parent=target, tree_id=target.tree_id).count()
        elif position == 'first-child':
            new_pos = 0
        elif position == 'left':
            new_pos = target.position
        elif position == 'right':
            new_pos = target.position + 1
        else:
            raise Exception('position not supported: %s' % position)
        for pl in CMSPlugin.objects.filter(language=language, parent=target.parent_id, tree_id=target.tree_id, position__gte=new_pos):
            pl.position += 1
            pl.save()
    else:
        new_pos = CMSPlugin.objects.filter(language=language, parent__isnull=True, placeholder=placeholder).count()

    plugin_base = CMSPlugin(
        plugin_type=plugin_type,
        placeholder=placeholder,
        position=new_pos,
        language=language
    )
    plugin_base.insert_at(target, position=position, save=False)

    plugin = plugin_model(**data)
    plugin_base.set_base_attr(plugin)
    plugin.save()
    return plugin
Exemple #12
0
def add_plugin(placeholder,
               plugin_type,
               language,
               position='last-child',
               **data):
    """
    Taken from django-cms api (in newer versions)
    https://github.com/divio/django-cms/blob/b8633b42efcd137d96e1e3f42e004cb7595768fe/cms/api.py
    """
    assert isinstance(placeholder, Placeholder)
    plugin_model = plugin_type.model
    plugin_type = plugin_type.__name__
    plugin_base = CMSPlugin(plugin_type=plugin_type,
                            placeholder=placeholder,
                            position=1,
                            language=language)
    plugin_base.insert_at(None, position='last-child', commit=False)
    plugin = plugin_model(**data)
    plugin_base.set_base_attr(plugin)
    plugin.save()
    return plugin
Exemple #13
0
    def test_11_copy_textplugin(self):
        """
        Test that copying of textplugins replaces references to copied plugins
        """
        
        page = self.create_page()
        
        placeholder = page.placeholders.get(slot='body')
        
        plugin_base = CMSPlugin(
            plugin_type='TextPlugin',
            placeholder=placeholder, 
            position=1, 
            language=self.FIRST_LANG)
        plugin_base.insert_at(None, position='last-child', commit=False)
                
        plugin = Text(body='')
        plugin_base.set_base_attr(plugin)
        plugin.save()
        
        plugin_ref_1_base = CMSPlugin(
            plugin_type='TextPlugin',
            placeholder=placeholder, 
            position=1, 
            language=self.FIRST_LANG)
        plugin_ref_1_base.insert_at(plugin_base, position='last-child', commit=False)    
        
        plugin_ref_1 = Text(body='')
        plugin_ref_1_base.set_base_attr(plugin_ref_1)
        plugin_ref_1.save()
        
        plugin_ref_2_base = CMSPlugin(
            plugin_type='TextPlugin',
            placeholder=placeholder, 
            position=2, 
            language=self.FIRST_LANG)
        plugin_ref_2_base.insert_at(plugin_base, position='last-child', commit=False)    
        
        plugin_ref_2 = Text(body='')
        plugin_ref_2_base.set_base_attr(plugin_ref_2)

        plugin_ref_2.save()
        
        plugin.body = plugin_tags_to_admin_html(' {{ plugin_object %s }} {{ plugin_object %s }} ' % (str(plugin_ref_1.pk), str(plugin_ref_2.pk)))
        plugin.save()
        self.assertEquals(plugin.pk, 1)
        page_data = self.get_new_page_data()

        #create 2nd language page
        page_data.update({
            'language': self.SECOND_LANG,
            'title': "%s %s" % (page.get_title(), self.SECOND_LANG),
        })
        response = self.client.post(URL_CMS_PAGE_CHANGE % page.pk + "?language=%s" % self.SECOND_LANG, page_data)
        self.assertRedirects(response, URL_CMS_PAGE)
        
        self.assertEquals(CMSPlugin.objects.filter(language=self.FIRST_LANG).count(), 3)
        self.assertEquals(CMSPlugin.objects.filter(language=self.SECOND_LANG).count(), 0)
        self.assertEquals(CMSPlugin.objects.count(), 3)
        self.assertEquals(Page.objects.all().count(), 1)
        
        copy_data = {
            'placeholder': placeholder.pk,
            'language': self.SECOND_LANG,
            'copy_from': self.FIRST_LANG,
        }
        response = self.client.post(URL_CMS_PAGE + "copy-plugins/", copy_data)
        self.assertEquals(response.status_code, 200)
        self.assertEqual(response.content.count('<li '), 3)
        # assert copy success
        self.assertEquals(CMSPlugin.objects.filter(language=self.FIRST_LANG).count(), 3)
        self.assertEquals(CMSPlugin.objects.filter(language=self.SECOND_LANG).count(), 3)
        self.assertEquals(CMSPlugin.objects.count(), 6)

        new_plugin = Text.objects.get(pk=6)
        self.assertEquals(plugin_tags_to_id_list(new_plugin.body), [u'4', u'5'])
Exemple #14
0
def add_plugin(placeholder, plugin_type, language, position='last-child',
               target=None, **data):
    """
    Add a plugin to a placeholder

    See docs/extending_cms/api_reference.rst for more info
    """
    # validate placeholder
    assert isinstance(placeholder, Placeholder)

    # validate and normalize plugin type
    plugin_model, plugin_type = _verify_plugin_type(plugin_type)
    if target:
        if position == 'last-child':
            if CMSPlugin.node_order_by:
                position = 'sorted-child'
            new_pos = CMSPlugin.objects.filter(parent=target).count()
            parent_id = target.pk
        elif position == 'first-child':
            new_pos = 0
            if CMSPlugin.node_order_by:
                position = 'sorted-child'
            parent_id = target.pk
        elif position == 'left':
            new_pos = target.position
            if CMSPlugin.node_order_by:
                position = 'sorted-sibling'
            parent_id = target.parent_id
        elif position == 'right':
            new_pos = target.position + 1
            if CMSPlugin.node_order_by:
                position = 'sorted-sibling'
            parent_id = target.parent_id
        else:
            raise Exception('position not supported: %s' % position)
        if position == 'last-child' or position == 'first-child':
            qs = CMSPlugin.objects.filter(language=language, parent=target, position__gte=new_pos,
                                          placeholder=placeholder)
        else:
            qs = CMSPlugin.objects.filter(language=language, parent=target.parent_id, position__gte=new_pos,
                                          placeholder=placeholder)
        for pl in qs:
            pl.position += 1
            pl.save()
    else:
        if position == 'last-child':
            new_pos = CMSPlugin.objects.filter(language=language, parent__isnull=True, placeholder=placeholder).count()
        else:
            new_pos = 0
            for pl in CMSPlugin.objects.filter(language=language, parent__isnull=True, position__gte=new_pos,
                                               placeholder=placeholder):
                pl.position += 1
                pl.save()
        parent_id = None
    plugin_base = CMSPlugin(
        plugin_type=plugin_type,
        placeholder=placeholder,
        position=new_pos,
        language=language,
        parent_id=parent_id,
    )

    plugin_base = plugin_base.add_root(instance=plugin_base)

    if target:
        plugin_base = plugin_base.move(target, pos=position)
    plugin = plugin_model(**data)
    plugin_base.set_base_attr(plugin)
    plugin.save()
    return plugin
def convert(request, slug = "dryrun"):
    # this dictionary store the information for the conversions
    execute=slug
    models_dictionary = {
        "messages": {},                             # a general set of messages for the user
        "modules":  {
            "news_and_events.models": {             # each module containing the models must be represented, like this
                "application": "News & Events",     # this is the human-friendly name of the module
                "models": {                         # a dictionary with each model in that module
                    "NewsArticle": {                # the actual name of the class
                        "fields": [                 # a list of the fields we're working on
                            {                       # a dictionary for each field
                                "old_field": "content",
                                "new_field": "body",                
                                "slot": "body",
                                },
                            ],
                        "model": "News articles",   # the human-friendly name of the model
                        "actions": {},              # an empty dictionary where we we store the results
                        },
                    "Event": {                      # a second model in that module
                        "fields": [                 
                            {                       
                                "old_field": "content",
                                "new_field": "body",                
                                "slot": "body",
                                },
                            ],
                        "model": "Events",
                        "actions": {},
                        },
                    },
                },
            "vacancies_and_studentships.models": {  # and a second module
                "application": "Vacancies & Studentships",
                "models": {
                    "Vacancy": {
                        "fields": [                 
                            {                       
                                "old_field": "description",
                                "new_field": "body",                
                                "slot": "body",
                                },
                            ],
                        "model": "Vacancies",
                        "actions": {},
                        },
                    "Studentship": {
                        "fields": [                 
                            {                       
                                "old_field": "description",
                                "new_field": "body",                
                                "slot": "body",
                                },
                                ],
                        "model": "Studentships",
                        "actions": {},
                        },
                    },
                },
            "publications.models": {                
                "application": "Publications",
                "models": {
                    "Researcher": {
                        "fields": [                 
                            {                       
                                "old_field": "research_synopsis",
                                "new_field": "synopsis_of_research",                
                                "slot": "body",
                                },
                            {                       
                                "old_field": "research_description",
                                "new_field": "description_of_research",                
                                "slot": "body",
                                },
                            ],
                        "model": "Researcher",
                        "actions": {},
                        },
                    },
                },
            },
        }

    # loop over the modules
    for module, module_values in models_dictionary["modules"].items():

        # loop over the models in the module
        for model, model_values in module_values["models"].items():
            
            # mmodel is the human-readable name of the model, used for the report summary
            mmodel = models_dictionary["modules"][module]["models"][model]["model"]
            models_dictionary["messages"][mmodel]={}

            # import the model
            actual_model = getattr(__import__(module, globals(), locals(), module_values["models"], -1), model)
                                            
            # loop over the fields that need converting
            for field in model_values["fields"]:
                print field

                
                old_field = field["old_field"]
                new_field = field["new_field"]
                slot = field["slot"]

                # create a summary report for this field
                models_dictionary["messages"][mmodel][old_field]={}

                try:
                    getattr(actual_model, new_field)
                except AttributeError:
                    message = "field " + new_field + " is missing - check the model and try agin"
                    models_dictionary["messages"][mmodel][old_field]["Error"]=message
                    continue
                    
                junk_content = []   # a record of those items with nothing but <br /> in them
                moved_items =[]     # a record of the items we migrated to placeholders

                # loop over each item in the class
                for item in actual_model.objects.all():

                    old_field_content = getattr(item, old_field)  # the old field we want to convert

                    # first get rid of junk content (change "<br />" to "")
                    if old_field_content == "<br />":
                        old_field_content = ""
                        setattr(item, old_field, "") # item.content = ""
                        if execute == "convert":
                            item.save()
                    
                    # now the serious business of converting the fields
            
                    # if the item lacks a placeholder, create the placeholder and the reference to it
                    if old_field_content and not getattr(item, new_field, None):

                        # check to see if it's worth converting
                        if len(old_field_content) > 60:

                            # create the placeholder
                            placeholder=Placeholder(slot=slot)
                            if execute == "convert":
                                placeholder.save()
        
                            # refer to the placeholder from the item
                            setattr(item, new_field, placeholder)
        
                            # I copied this from one of the test files
                            plugin_base = CMSPlugin(
                                plugin_type='TextPlugin',
                                placeholder=placeholder, 
                                position=1, 
                                language=settings.LANGUAGES[0][0]) # we assume the original field was in the first language
                            plugin_base.insert_at(None, position='last-child', commit=False)
        
                            # create a text plugin
                            plugin = Text(body='')
                            plugin_base.set_base_attr(plugin)
                            plugin.body = getattr(item, old_field)
                            if execute == "convert":
                                plugin.save()
        
                            # set the old field to ""
                            setattr(item, old_field, "")
                            if execute == "convert":
                                item.save()
                                item.status = "Converted to placeholder"
                            else:
                                item.status = "Unconverted"
                                        
                        else:
                            print "too short", old_field_content
                            # this item is so short it must be junk
                            if execute == "convert":
                                setattr(item, old_field, "")
                                item.status = "Junk field - too short; was deleted instead of converted:" + old_field_content
                                item.save()
                            else:    
                                item.status = "Junk field - too short; will be deleted instead of converted:" + old_field_content
                            # make a note that this was a junk item
                            junk_content.append(item)
                                # make a note that we moved this item

                        moved_items.append(item)    
 
                # information about junk content items
                if execute == "convert":
                    message = " ".join((str(len(junk_content)), "junk items not converted items"))
                else:
                    message = " ".join((str(len(junk_content)), "junk items found"))                    

                models_dictionary["messages"][mmodel][old_field]["Junk fields"]=message

                # information about items that have been/need to be converted
                if execute == "convert":
                    message = str(len(moved_items)) + " items were converted to placeholder " + new_field
                else:
                    message = str(len(moved_items)) + " items need to be converted to placeholder " + new_field
            
                models_dictionary["messages"][mmodel][old_field]["Conversions"]=message
            
                # list every item that was copied for the full report
                if execute == "convert":
                    action = "Fields that were copied"
                else:
                    action = "Fields to be copied"
                    
                models_dictionary["modules"][module]["models"][model]["actions"][action]=moved_items
                

    return shortcuts.render_to_response(
        "housekeeping/convert_to_placeholders.html", {
            "execute": execute,
            "converted": models_dictionary,
            },
        RequestContext(request),
        )
Exemple #16
0
def add_plugin(placeholder, plugin_type, language, position='last-child',
               target=None, **data):
    """
    Add a plugin to a placeholder

    See docs/extending_cms/api_reference.rst for more info
    """
    # validate placeholder
    assert isinstance(placeholder, Placeholder)

    # validate and normalize plugin type
    plugin_model, plugin_type = _verify_plugin_type(plugin_type)
    if target:
        if position == 'last-child':
            if CMSPlugin.node_order_by:
                position = 'sorted-child'
            new_pos = CMSPlugin.objects.filter(parent=target).count()
            parent_id = target.pk
        elif position == 'first-child':
            new_pos = 0
            if CMSPlugin.node_order_by:
                position = 'sorted-child'
            parent_id = target.pk
        elif position == 'left':
            new_pos = target.position
            if CMSPlugin.node_order_by:
                position = 'sorted-sibling'
            parent_id = target.parent_id
        elif position == 'right':
            new_pos = target.position + 1
            if CMSPlugin.node_order_by:
                position = 'sorted-sibling'
            parent_id = target.parent_id
        else:
            raise Exception('position not supported: %s' % position)
        if position == 'last-child' or position == 'first-child':
            qs = CMSPlugin.objects.filter(language=language, parent=target, position__gte=new_pos,
                                          placeholder=placeholder)
        else:
            qs = CMSPlugin.objects.filter(language=language, parent=target.parent_id, position__gte=new_pos,
                                          placeholder=placeholder)
        for pl in qs:
            pl.position += 1
            pl.save()
    else:
        if position == 'last-child':
            new_pos = CMSPlugin.objects.filter(language=language, parent__isnull=True, placeholder=placeholder).count()
        else:
            new_pos = 0
            for pl in CMSPlugin.objects.filter(language=language, parent__isnull=True, position__gte=new_pos,
                                               placeholder=placeholder):
                pl.position += 1
                pl.save()
        parent_id = None
    plugin_base = CMSPlugin(
        plugin_type=plugin_type,
        placeholder=placeholder,
        position=new_pos,
        language=language,
        parent_id=parent_id,
    )

    plugin_base = plugin_base.add_root(instance=plugin_base)

    if target:
        plugin_base = plugin_base.move(target, pos=position)
    plugin = plugin_model(**data)
    plugin_base.set_base_attr(plugin)
    plugin.save()
    return plugin