Versioner sammenlignet

Nøgle

  • Linjen blev tilføjet.
  • Denne linje blev fjernet.
  • Formatering blev ændret.

...

Kodeblok
networks:
  bridge:
    driver: bridge
services:
  # The container that runs XWiki in Tomcat, with the appropriate JDBC driver (for postgres).
  web:
    image: "xwiki:${XWIKI_VERSION}-postgres-tomcat"
    container_name: xwiki-postgres-tomcat-web
    depends_on:
      - db
    ports:
      - "8080:8080"
    # Default values defined in .env file.
    # The DB_USER/DB_PASSWORD/DB_DATABASE/DB_HOST variables are used in the hibernate.cfg.xml file.
    environment:
      - XWIKI_VERSION=${XWIKI_VERSION}
      - DB_USER=${DB_USER}
      - DB_PASSWORD=${DB_PASSWORD}
      - DB_DATABASE=${DB_DATABASE}
      - DB_HOST=xwiki-postgres-db
      - JAVA_OPTS="-Xmx2048m"
	  - TZ="Europe/Copenhagen"
    # Provide a name instead of an auto-generated id for xwiki data (the permanent directory in included in it)
    # configured in the Dockerfile, to make it simpler to identify in 'docker volume ls'.
    volumes:
      - /opt/xwiki/xwiki-data:/usr/local/xwiki
    networks:
      - bridge
  # The container that runs the database (postgres)
  db:
    image: "postgres:17"
    container_name: xwiki-postgres-db
    volumes:
      - /opt/xwiki/postgres-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_ROOT_PASSWORD=${POSTGRES_ROOT_PASSWORD}
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_USER=${DB_USER}
      - POSTGRES_DB=${DB_DATABASE}
      - POSTGRES_INITDB_ARGS=--encoding=UTF8 --locale-provider=builtin --locale=C.UTF-8
    networks:
      - bridge

...

Kodeblok
1st page under sandbox:

https://funky.mos-eisley.dk/rest/wikis/xwiki/spaces/Sandbox/spaces/AtlassianHome/pages/sub1WebHome - page under Sandbox

Sub pargepage "Page2" for Page 1AtlassianHome:

https://funky.mos-eisley.dk/rest/wikis/xwiki/spaces/Sandbox/spaces/AtlassianHome/spaces/sub1Page2/pages/sub2WebHome

Sub parge for Page 2:

https://funky.mos-eisley.dk/rest/wikis/xwiki/spaces/Sandbox/spaces/sub1/spaces/sub2/pages/sub3

Migration script (WIP):

etc etc


Migration script (WIP):

Kodeblok
from atlassian import Confluence
import convert
import 
Kodeblok
from atlassian import Confluence
import convert
import requests
from requests.auth import HTTPBasicAuth
from xml.sax.saxutils import escape
import os
import config
from slugify import slugify

confluence = Confluence(
    url=config.conflunce_url,
    username=config.username,
    password=config.password)

def processmake_all_childrenslug(pagetitle):

    return ""

def create_xwki_page(wiki_space,title,parent,content):

slug = slugify(title)
    url = config.xwiki_url + "/rest/wikis/xwiki/spaces/" + wiki_space + "/pages/" + title.replace(" ","")
return slug

def when_to_xwiki_datetime(when):

    
# Incoming from Confluence xml = "<page xmlns=\"http://www.xwiki.org\"><title>" + title + "</title>"
    xml = xml + "<parent>" + wiki_space + "." + parent.replace(" ","") + "</parent>"
    xml = xml + "<syntax>xwiki/2.1</syntax>"
    xml = xml + "<content>" +  escape(content) + "</content></page>REST: 2011-09-06T12:03:35.000+02:00
    # Return format: 2025-09-28 10:00:00

    return when.replace("T"," ").replace(".000+02:00","")
    
def create_xwki_page(confluence_page_id,title,parent_url,xwiki_path,content,when,page_type):

    cont_bool = False
    slug = make_slug(title)
    url = parent_url + "/spaces/" + slug + "/pages/WebHome"

    #print (xml)

    headers = {(result, log) = convert.convert(xwiki_path + "." + slug,content)
   
    xml "Content-Type": "application/xml= "<page xmlns=\"http://www.xwiki.org\">"
    }

xml = xml + response"<title>" = requests.put(url, data=xml, headers=headers, auth=HTTPBasicAuth(config.username,config.password))

+ title + "</title>"
    #xml Check= thexml response
    if response.status_code == 201:+ "<syntax>xwiki/2.1</syntax>"
    xml = xml + print("Page <content>" + title escape(result) + " created")</content></page>"

    else:
headers =  {
     if response.status_code == 202: "Content-Type": "application/xml"
    }

    response = requests.put(url,  print("Page " + title + " updated")data=xml, headers=headers, auth=HTTPBasicAuth(config.username,config.password))

    #Check the response
    if response.status_code ==  else201:
        print("Page " + title print("Status code:", response.status_code+ " created (" + page_type + ")")
        cont_bool = True
  print("Response:", response.text)

def attach_file_to_page(wiki_space,title,file_path,filename):

 else:
       url =if configresponse.xwikistatus_urlcode + "/rest/wikis/xwiki/spaces/== 202:
            print("Page " + wiki_spacetitle + "/pages/ updated (" + title.replace(" page_type + ",)"")
 + "/attachments/" + filename

           headerscont_bool = {True
        "Content-Type": "application/xml",
else:
            "XWiki-AttachmentComment": "Uploaded by migrator"
 print("Status code:", response.status_code)
   }
    
    with open(file_path, "rb") as fprint("Response:", response.text)


    if cont_bool == True:
    
    #files = {"file": f}  # #Labels
        responselabels = requests.put(url, data=f, headers=headers, auth=HTTPBasicAuth(config.username,config.password))

confluence.get_page_labels(confluence_page_id, prefix=None, start=None, limit=None)
    # Check the response
 for label  if response.status_code == 201:
in labels["results"]:

        print("Attachment     attach_label_to_page(parent_url + "/spaces/" + filenameslug + " created")
    else:/pages/WebHome",label["name"])

        if response.status_code == 202:#Attachments
        #TO    print("Attachment " + filename + " updated")
DO: https://www.mos-eisley.dk/spaces/it/pages/57245722/Commodore+C64 - more than 50 attachments... only 50 downloaded
        #Gitgus else:issue: https://github.com/atlassian-api/atlassian-python-api/issues/1590
        directory =   print("Status code:", response.status_code)"attachments/" + confluence_page_id
            print("Response:", response.text)

#Start on the XWiki
wiki_space = "Sandbox" 

#Start Space in Confluence
space_key = "ATLASSIAN"

spaceos.makedirs(directory, exist_ok=True)

        attachments = confluence.get_space(space_key, expand='description.plain,homepage')
homepageid=space['homepage']['id']
prop = confluence.get_page_by_id(homepageid,expand="body.storage")
content = prop["body"]["storage"]["value"]
home_title = prop['title']

(result, log) = convert.convert(content)

xwiki_page = create_xwki_page(wiki_space,home_title,"webHome",result)
parent = home_title
children = confluence.get_page_child_by_type(homepageid, type='page', start=None, limit=None, expand=None)
for page in children:

    page_id = page["id"]

    page1 = confluence.get_page_by_id(page_id=page_id,expand="body.storage")
    content = page1["body"]["storage"]["value"]
    title = page['title']

    #Labels
    #confluence.get_page_labels(page_id, prefix=None, start=None, limit=None)

    #Attachments
    directory = "attachments/" + page_id
    os.makedirs(directory, exist_ok=True)
    (result, log) = convert.convert(content)

    xwiki_page = create_xwki_page(wiki_space,title,parent,result)
    #exit(0)
    attachments = confluence.download_attachments_from_page(page_id, path=directory)
   
    with os.scandir(directory) as entries:
        for entry in entries:
            if entry.is_file():
                attach_file_to_page(wiki_space,title,entry.path,entry.name)
  

    parent = titledownload_attachments_from_page(confluence_page_id, path=directory)
   
        with os.scandir(directory) as entries:
            for entry in entries:
                if entry.is_file():
                    attach_file_to_page(parent_url + "/spaces/" + slug + "/pages/WebHome",entry.path,entry.name)
    
    if page_type == "Page":

        #Children
        children = confluence.get_page_child_by_type(confluence_page_id, type='page', start=None, limit=None, expand=None)
        for page in children:

            page_id = page["id"]

            page1 = confluence.get_page_by_id(page_id=page_id,expand="body.storage,version")
            content = page1["body"]["storage"]["value"]
            when = prop["version"]["when"]
            title = page['title']

            print ("Preparing: " + title)
        
            xwiki_page = create_xwki_page(page_id,title,parent_url + "/spaces/" + slug,xwiki_path + "." + slug,content,when,"Page")
    
    if page_type == "Blogpost":

        change_to_blog_post(url,slug,when)
        

def change_to_blog_post(url,slug,when):

    url = url + "/objects"

    xml = "<object xmlns=\"http://www.xwiki.org\">"
    xml = xml + "<className>Blog.BlogPostClass</className>"
    xml = xml + "<properties><property>"
    xml = xml + "<name>publishDate</name>"
    xml = xml + "<value>" + when_to_xwiki_datetime(when) + "</value>"
    xml = xml + "</property><property>"
    xml = xml + "<name>category</name><value>General</value></property></properties></object>"

    headers = {
        "Content-Type": "application/xml"
    }

    response = requests.post(url, data=xml, headers=headers, auth=HTTPBasicAuth(config.username,config.password))

    #Check the response
    if response.status_code == 201:
        print("Blog " + slug + " created")
        cont_bool = True
    else:
        if response.status_code == 202:
            print("Page " + title + " updated")
            cont_bool = True
        else:
            print("Status code:", response.status_code)
            print("Response:", response.text)    
    
def attach_file_to_page(url,file_path,filename):

    url = url + "/attachments/" + filename

    headers = {
        "Content-Type": "application/xml",
        "XWiki-AttachmentComment": "Uploaded by migrator"
    }
    
    with open(file_path, "rb") as f:
        #files = {"file": f}  # 
        response = requests.put(url, data=f, headers=headers, auth=HTTPBasicAuth(config.username,config.password))

    # Check the response
    if response.status_code == 201:
        print("Attachment " + filename + " created")
    else:
        if response.status_code == 202:
            print("Attachment " + filename + " updated")
        else:
            print("Status code:", response.status_code)
            print("Response:", response.text)

def attach_label_to_page(url,label):

    url = url + "/objects"

    headers = {
        "Content-Type": "application/xml",
    }

    xml = "<object xmlns=\"http://www.xwiki.org\">"
    xml = xml + "<className>XWiki.TagClass</className>"
    xml = xml + "<property name=\"tags\">"
    xml = xml + "<value>" + label + "</value>"
    xml = xml + " </property></object>"

    response = requests.post(url, data=xml, headers=headers, auth=HTTPBasicAuth(config.username,config.password))

    # Check the response
    if response.status_code == 201:
        print("Page " + title + " created")
    else:
        if response.status_code == 202:
            print("Page " + title + " updated")
        else:
            print("Status code:", response.status_code)
            print("Response:", response.text)


#Start on the XWiki
wiki_space = "Main" # XWiki Home
#wiki_space = "Sandbox" # XWki Sandbox

#Space to migrate in Confluence - Capital and lower case can be tricky
#Pages on same level as Home page is not migrated, only the tree structure from Home
space_key = "familieblog"

space = confluence.get_space(space_key, expand='description.plain,homepage')
homepage_id=space['homepage']['id']

# Blogposts
blog_posts = confluence.get_all_pages_from_space_as_generator(space_key, start=0, limit=1000, status=None, expand=None, content_type='blogpost')
for blog in blog_posts:

    blog_id=blog["id"]
    prop = confluence.get_page_by_id(blog_id,expand="body.storage,version")
    content = prop["body"]["storage"]["value"]
    when = prop["version"]["when"]
    title = prop['title']
    create_xwki_page(homepage_id,title, config.xwiki_url + "/rest/wikis/xwiki/spaces/Blog",wiki_space,content,when,"Blogpost")

exit(0)

prop = confluence.get_page_by_id(homepage_id,expand="body.storage,version")
content = prop["body"]["storage"]["value"]
when = prop["version"]["when"]
title = prop['title']

xwiki_page = create_xwki_page(homepage_id,title, config.xwiki_url + "/rest/wikis/xwiki/spaces/" + wiki_space,wiki_space,content,when,"Page")


Kodeblok
# https://github.com/faktorzehn/confluence2xwiki/blob/master/convert.py

from bs4 import BeautifulSoup
import bs4
from slugify import slugify

def make_slug(title):

    slug = slugify(title)
    return slug

log_string = ""

def log(msg):
	global log_string
	log_string += msg + "\n"

def parse_li(xwiki_path,element):
	return parse(xwiki_path,element.contents)

def parse_br(xwiki_path,element):
	return "\n"

def parse_em(xwiki_path,element): 
	return "//" + parse(xwiki_path,element.contents) + "//"

def parse_h1(xwiki_path,element):
	return "\n" + "= " + parse(xwiki_path,element.contents) + " =\n"

def parse_h2(xwiki_path,element):
	return "\n" + "== " + parse(xwiki_path,element.contents) + " =="

def parse_h3(xwiki_path,element):
	return "\n" + "=== " + parse(xwiki_path,element.contents) + " ==="
	
def parse_h4(xwiki_path,element):
	return "\n" + "==== " + parse(xwiki_path,element.contents) + " ===="

def parse_h5(xwiki_path,element):
	return "\n" + "===== " + parse(xwiki_path,element.contents) + " ====="

def parse_h6(xwiki_path,element):
	return "\n" + "====== " + parse(xwiki_path,element.contents) + " ======"

def parse_strong(xwiki_path,element): #bold
	return "**" + parse(xwiki_path,element.contents) + "**"
	
def parse_div(xwiki_path,element):
	return parse(xwiki_path,element.contents)

def parse_p(xwiki_path,element):
	return "\n" + parse(xwiki_path,element.contents).strip() + "\n"
	
def parse_u(xwiki_path,element):
	return "__" + parse(xwiki_path,element.contents).strip() + "__"
	
def parse_span(xwiki_path,element):
	return parse(xwiki_path,element.contents)
	
def parse_a(xwiki_path,element):
	if hasattr(element, "attrs"):
		if "href" in element.attrs:
			if parse(xwiki_path,element.contents) == element.attrs["href"]:
				return "[[" + element.attrs["href"] + "]]"
			else:
				return "[[" + parse(xwiki_path,element.contents) + ">>" + element.attrs["href"] + "]]"
		
		if "name" in element.attrs:
			log("Skipping anchor " + element.attrs["name"])
			return ""
			
		else:
			#raise Exception("Missing attributes")
			return ""
	else:
		raise Exception("Missing attributes 2")
	
def parse_ac_emoticon(xwiki_path,element):
	emoticons = {"smile": ":)", "wink": ";)", "yellow-star": "(*)", "tick": "(/)", "warning": "(!)", "question": "(?)"}
	
	name = element.attrs["ac:name"]
	
	if name in emoticons:
		return emoticons[name]
	else:
		log("Unkown emoticon " + name)
		return "(" + name + ")"


def parse_table(xwiki_path,element):
	data = []
	
	table_body = element.find('tbody')
	
	text = "\n"
	
	for row in table_body.find_all('tr'):		
		for col in row.contents:
			if col.name == "th" or col.name == "td":
				span = 1 if "colspan" not in col.attrs else int(col.attrs["colspan"])
				seperator = "|= " if col.name == "th" else "| "
				
				for i in range (0, span):
					if i == 0:
						text += seperator + parse(xwiki_path,col.contents).strip().replace("\n\n", "\n")
					else:
						text += seperator
			
		text += "\n"
		
	return(text)

def create_list(xwiki_path,element, syntax):
	text = ""	
	rows = element.find_all("li")
	
	for row in rows:
		text += "\n" + syntax + " " + parse(xwiki_path,row).strip()
		
	return text
	
def parse_dl(xwiki_path,element):
	return "\n"
	
def parse_ol(xwiki_path,element): #numbered list
	return create_list(xwiki_path,element, "1.")
	
def parse_ul(xwiki_path,element): #bulletpoints
	return create_list(xwiki_path,element, "* ")
	
def parse_code(xwiki_path,element):
	return "##" + parse(xwiki_path,element.contents) + "##"
	
def parse_pre(xwiki_path,element):
	return parse_code(xwiki_path,element)
	
def create_link(label, destination):
	if label == destination:
		return "[[" + destination + "]]"
	else:
		return "[[" + label + ">>" + destination + "]]"

def parse_ac_link(xwiki_path,element): #link
	label = destination = ""

	for link in element.contents:
		if link.name == "ri:page":
			label = destination = link.attrs["ri:content-title"]
		elif link.name == "ri:space":
			label = destination = link.attrs["ri:space-key"]
		
		elif link.name == "ac:plain-text-link-body":
			label = link.text
		
		elif type(link) == bs4.element.NavigableString and str(link) == "\n":
			continue
		elif link.name == "contentbylabel":
			continue
		
		else:
			log("Ignoring link of type " + link.name)
			return ""
	
	return create_link(label, destination)

def parse_ac_image(xwiki_path,element):
	#NPN Fix
	if element.find("ri:attachment") != None :
		return "[[image:" + element.find("ri:attachment").attrs["ri:filename"] + "]]"
	else:
		return ""

def parse_ac_structured_macro(xwiki_path,element):
	if element.attrs["ac:name"] == "include":
		return "{{include reference=\"" + xwiki_path + "." + make_slug(element.find("ri:page").attrs["ri:content-title"]) + ".WebHome\"/}}"
	
	elif element.attrs["ac:name"] == "excerpt-include":
		return create_link("include", element.find("ri:page").attrs["ri:content-title"])
	
	elif element.attrs["ac:name"] == "me-image":
		for parameter in element.findAll("ac:parameter"):
			acname = parameter.attrs["ac:name"]
			if acname == "image":
				image = parameter.text
			if acname == "path":
				path = parameter.text
			if acname == "group":
				group = parameter.text
			if acname == "thumbsize":
				thumbsize = parameter.text
			displaysize = "800"
			if acname == "displaysize":
				displaysize = parameter.text
		return "[[image:https://www.server.dk/data/" + path + "/" + image + "||data-xwiki-image-style-alignment=\"center\" data-xwiki-image-style-border=\"true\" width=\"" + displaysize + "\"]]"
	
	elif element.attrs["ac:name"] == "gallery":
		#https://extensions.xwiki.org/xwiki/bin/view/Extension/AttachmentGalleryMacro#Attachments
		return "{{velocity}}\n#set ($attachments = $doc.attachmentList)\n#if ($attachments.size() > 0)\n{{gallery}}\n#foreach($attachment in $attachments)\n#if($attachment.isImage())\n[[image:$attachment.filename]]\#end\n#end\n{{/gallery}}#end\n{{/velocity}}"
	
	elif element.attrs["ac:name"] == "brickset":
		for parameter in element.findAll("ac:parameter"):
			acname = parameter.attrs["ac:name"]
			if acname == "LID":
				lid = parameter.text
			if acname == "Name":
				bname = parameter.text

		return "== " + bname + " == [[image:http://images.brickset.com/sets/images/" + lid + "-1.jpg]]\n"
	
	elif element.attrs["ac:name"] == "code":
		language = element.find("ac:parameter")
		body = element.find("ac:plain-text-body").text
		if language == None:
			return "\n\n{{code}}\n" + body + "\n{{/code}}\n"
		else:
			return "\n\n{{code language=\"" + language.text + "\"}}\n" + body + "\n{{/code}}\n"
	
	elif element.attrs["ac:name"] == "excerpt":
		log("Removing excerpt")
		return parse(xwiki_path,element.find("ac:rich-text-body").contents)
	
	elif element.attrs["ac:name"] == "toc":
		return("{{toc/}}")
	
	elif element.attrs["ac:name"] == "panel":
		return parse(xwiki_path,element.find("ac:rich-text-body").contents)
	
	elif element.attrs["ac:name"] == "details":
		return parse(xwiki_path,element.find("ac:rich-text-body").contents)
	
	elif element.attrs["ac:name"] == "warning":
		return "{{error}}" + parse(xwiki_path,element.find("ac:rich-text-body").contents).strip() + "{{/error}}\n\n"
	elif element.attrs["ac:name"] == "note":
		return "{{warning}}" + parse(xwiki_path,element.find("ac:rich-text-body").contents).strip() + "{{/warning}}\n\n"
	elif element.attrs["ac:name"] == "info":
		return "{{info}}" + parse(xwiki_path,element.find("ac:rich-text-body").contents).strip() + "{{/info}}\n\n"
	elif element.attrs["ac:name"] == "tip":
		return "{{success}}" + parse(xwiki_path,element.find("ac:rich-text-body").contents).strip() + "{{/success}}\n\n"
	
	
	else:
		log("Ignoring structured macro of type " + element.attrs["ac:name"])
		return ""
	
def parse_ac_macro(xwiki_path,element):
	return parse_ac_structured_macro(element)

def parse_ac_layout(xwiki_path,element): #column layout
	text = ""
	
	sections = element.findAll("ac:layout-section")	
	for section in sections:
		if(section.attrs["ac:type"] == "single"):
			text += parse(xwiki_path,section.find("ac:layout-cell").contents).strip() + "\n"
		else:		
			text += "{{container layoutStyle=\"columns\"}}\n"			
			cells = section.findAll("ac:layout-cell")
			for cell in cells:
				text += "(((" + parse(xwiki_path,cell.contents).strip() + ")))\n"
			
			text += "{{/container}}\n"
			
	return text

def parse_ac_task_list(xwiki_path,element):
	text = "\n"
	
	for entry in element.findAll("ac:task", recursive = False):
		text +=  "* " + parse(entry.find("ac:task-body").contents).strip() + "\n"
	
	return text
	
	
def parse(xwiki_path,element):
	if isinstance(element, list):
		buffer = ""
		for child in element:
			buffer = buffer + parse(xwiki_path,child)
		return buffer
	
	if type(element) == bs4.element.NavigableString:
		if str(element) == "\n":
			return ""
		else:
			return str(element).replace("--", "~-~-")
	
	ignored = ["ac_placeholder"]
	name = str(element.name).replace("-", "_").replace(":", "_")
	
	if name in ignored:
		return ""
		
	# search for matching parse function and call it
	elif "parse_" + name in globals():
		return globals()["parse_" + name](xwiki_path,element)
	
	else:
		log("unknown: " + name)
		return ""

def convert(xwiki_path,text):
	global log_string
	soup = BeautifulSoup(text, "html.parser")
	contents = soup.contents
	while "\n" in contents: contents.remove("\n")
	return (parse(xwiki_path,contents).strip(), log_string.strip())