package migration import ( "database/sql" "federated.computer/wp-sync-slowtwitch/services/slowtwitch" "federated.computer/wp-sync-slowtwitch/services/wordpress" "fmt" "slices" "strconv" "strings" ) type MigratePosts struct { SlowtwitchDatabase *sql.DB ResultsDatabase *sql.DB WordpressBaseUrl string WordpressUser string WordpressPassword string } func (migration MigratePosts) Execute() { slowtwitchPostIds, err := slowtwitch.GetAllPostIds(migration.SlowtwitchDatabase) if err != nil { panic("Could not migrate posts: " + err.Error()) } migratedPostIds, err := GetAllMigratedPostIds(migration.ResultsDatabase) if err != nil { panic("Could not migrate posts:" + err.Error()) } //get wordpress tag data, there are only 3 tags := []string{"swim", "bike", "run"} wpTagData, wpTagErr := wordpress.GetTags(tags, migration.WordpressBaseUrl, migration.WordpressUser, migration.WordpressPassword) if wpTagErr != nil { panic("Could not migrate posts due to tags not found:" + wpTagErr.Error()) } slowtwitchPostIdsForMigration := getPostIdsThatNeedMigration(slowtwitchPostIds, migratedPostIds) for _, postId := range slowtwitchPostIdsForMigration { errorMessage := "" //migrate postBase, postBaseErr := slowtwitch.GetPostBase(postId, migration.SlowtwitchDatabase) if postBaseErr != nil { errorMessage = errorMessage + postBaseErr.Error() createPostFailureResult(postId, errorMessage, migration.ResultsDatabase) continue } createWordpressPost := wordpress.CreatePost{ Title: postBase.Title, Excerpt: postBase.Description, Status: "publish", } if postBase.DatePublished.Valid { t := postBase.DatePublished.Time timeString := fmt.Sprintf("%d-%02d-%02dT%02d:%02d:%02d", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second()) createWordpressPost.Date = timeString } else { errorMessage = errorMessage + "Invalid Date Published" createPostFailureResult(postId, errorMessage, migration.ResultsDatabase) continue } for _, tag := range wpTagData { if postBase.Bike == true && tag.Name == "bike" { createWordpressPost.Tags = append(createWordpressPost.Tags, tag.Id) } if postBase.Swim == true && tag.Name == "swim" { createWordpressPost.Tags = append(createWordpressPost.Tags, tag.Id) } if postBase.Run == true && tag.Name == "run" { createWordpressPost.Tags = append(createWordpressPost.Tags, tag.Id) } } var wordPressCategoryIds []int var firstCategoryResult CategoryResult for _, slowtwitchCategoryId := range postBase.CategoryIds { categoryResult, err := GetSlowtwitchCategoryResult(slowtwitchCategoryId, migration.ResultsDatabase) if err != nil { errorMessage = errorMessage + err.Error() createPostFailureResult(postId, errorMessage, migration.ResultsDatabase) continue } wordPressCategoryIds = append(wordPressCategoryIds, categoryResult.WordpressId) firstCategoryResult = categoryResult } createWordpressPost.Categories = wordPressCategoryIds //Get Author ID editor, findEditorErr := GetEditor(postBase.Author, migration.ResultsDatabase) if findEditorErr != nil { errorMessage = errorMessage + findEditorErr.Error() createPostFailureResult(postId, errorMessage, migration.ResultsDatabase) continue } createWordpressPost.Author = editor.WordpressId //Get old link oldLink := strings.ReplaceAll(firstCategoryResult.OldUrl, "index.html", "") + slowtwitch.ConvertPostTitleToPath(postBase.Title, postBase.Id) linkStatus := slowtwitch.GetPageStatus(oldLink) if linkStatus == 404 { errorMessage = errorMessage + "Page not found on Slowtwitch" createPostFailureResult(postId, errorMessage, migration.ResultsDatabase) continue } //Get page, parse out post data and images //Upload images to wordpress, swap out with new image urls //Submit imagePaths, html, retreiveHtmlErr := slowtwitch.GetImagesAndPostHtml(oldLink) if retreiveHtmlErr != nil { errorMessage = errorMessage + retreiveHtmlErr.Error() createPostFailureResult(postId, errorMessage, migration.ResultsDatabase) continue } //Create images from the image paths var imageResults []ImageResult for i, imagePath := range imagePaths { //construct URL imageUrl := "https://www.slowtwitch.com" + imagePath createWordpressImage := wordpress.CreateImage{ Url: imageUrl, } //submit image wordpressImage, wordpressImageErr := createWordpressImage.Execute(migration.WordpressBaseUrl, migration.WordpressUser, migration.WordpressPassword) if wordpressImageErr != nil { errorMessage = errorMessage + wordpressImageErr.Error() createImageFailureResult(imageUrl, migration.ResultsDatabase) continue } //first photo is the featured photo if i == 0 { createWordpressPost.FeaturedMedia = wordpressImage.Id } //begin process of recording result imageResult := ImageResult{ OldUrl: imageUrl, NewUrl: wordpressImage.Link, WordpressId: wordpressImage.Id, IsSuccess: true, } imageResults = append(imageResults, imageResult) //replace old links with new in post html strings.ReplaceAll(html, imageUrl, wordpressImage.Link) //create redirect imageRedirect := wordpress.CreateRedirect{ Title: postBase.Title + "image-" + string((i + 1)), Url: imagePath, MatchType: "page", ActionType: "url", ActionCode: 301, GroupId: 1, ActionData: wordpress.ActionData{ Url: "/" + wordpressImage.Slug, }, } _, imageRedirectErr := imageRedirect.Execute(migration.WordpressBaseUrl, migration.WordpressUser, migration.WordpressPassword) if imageRedirectErr != nil { fmt.Println("Failed to create image redirect:", imageUrl, ":", imageRedirectErr.Error()) } } createWordpressPost.Content = html post, createWordpressPostErr := createWordpressPost.Execute(migration.WordpressBaseUrl, migration.WordpressUser, migration.WordpressPassword) if createWordpressPostErr != nil { errorMessage = errorMessage + createWordpressPostErr.Error() createPostFailureResult(postId, errorMessage, migration.ResultsDatabase) continue } //set up post result here to create //truncate error message for db if len(errorMessage) > 1450 { errorMessage = errorMessage[:1450] } postResult := PostResult{ SlowtwitchId: postId, WordpressId: post.Id, OldUrl: oldLink, OldUrlStatus: linkStatus, NewUrl: post.Link, IsSuccess: true, ErrorMessage: errorMessage, } postResultId, createPostResultErr := CreatePostResult(postResult, migration.ResultsDatabase) if createPostResultErr != nil { fmt.Println("Could not record post result for Slowtwitch post:" + strconv.Itoa(postId) + createPostResultErr.Error()) } for _, imageResult := range imageResults { imageResult.PostId = postResultId createImageResultErr := CreateImageResult(imageResult, migration.ResultsDatabase) if createImageResultErr != nil { fmt.Println("Error recording image result") } } oldPath := strings.ReplaceAll(oldLink, "https://www.slowtwitch.com", "") postRedirect := wordpress.CreateRedirect{ Title: "Article Redirect" + postBase.Title, Url: oldPath, MatchType: "page", ActionType: "url", ActionCode: 301, GroupId: 1, ActionData: wordpress.ActionData{ Url: "/" + strings.ReplaceAll(postResult.NewUrl, migration.WordpressBaseUrl, ""), }, } _, postRedirectErr := postRedirect.Execute(migration.WordpressBaseUrl, migration.WordpressUser, migration.WordpressPassword) if postRedirectErr != nil { fmt.Println("Error creating redirect for", postId, ":"+postRedirectErr.Error()) } fmt.Println("Successfully created post and result for", postId) // TODO Update advanced Custom Fields with images //Install ACF and create field /* "acf": { "post_images": [...ids] } */ } // TODO Update related posts (get from post results db) as second loop //Install ACF and create field /* "acf": { "related_posts": [...ids] } */ } func getPostIdsThatNeedMigration(slowtwitchPostIds, migratedPostIds []int) []int { var output []int for _, slowtwitchPostId := range slowtwitchPostIds { hasId := slices.Contains(migratedPostIds, slowtwitchPostId) if hasId == false { output = append(output, slowtwitchPostId) } } return output } func createPostFailureResult(slowtwitchId int, errorMessage string, migrationDb *sql.DB) { fmt.Println("Error creating post: ", slowtwitchId, ":", errorMessage) postResult := PostResult{ SlowtwitchId: slowtwitchId, WordpressId: 0, OldUrl: "", OldUrlStatus: 0, NewUrl: "", IsSuccess: false, ErrorMessage: errorMessage, } _, err := CreatePostResult(postResult, migrationDb) if err != nil { fmt.Println("Failed to create failure result: ", err) } } func createImageFailureResult(url string, resultsDatabase *sql.DB) { fmt.Println("Error creating image failure result: ", url) imageResult := ImageResult{ OldUrl: url, NewUrl: "", WordpressId: 0, IsSuccess: false, } err := CreateImageResult(imageResult, resultsDatabase) if err != nil { fmt.Println("Failed to create failure result: ", err) } }