├── .editorconfig ├── .gitattributes ├── .gitignore ├── LICENCE ├── README.md ├── admin └── src │ ├── assets │ └── prismjs.css │ ├── components │ ├── DataViewer │ │ ├── index.js │ │ └── styles.js │ ├── DropFileZone │ │ ├── DragAndDropIcon.js │ │ ├── index.js │ │ └── styles.js │ ├── FormatIcon │ │ └── index.js │ ├── ImportForm │ │ └── index.js │ ├── Layout │ │ └── index.js │ ├── MappingTable │ │ ├── TableBody.js │ │ ├── TableHeader.js │ │ ├── index.js │ │ └── styles.js │ ├── MediaPreview │ │ └── index.js │ ├── OptionsExport │ │ └── index.js │ ├── RawInputForm │ │ ├── index.js │ │ └── styles.js │ ├── UploadFileForm │ │ └── index.js │ └── common │ │ ├── Block │ │ ├── index.js │ │ └── styles.js │ │ ├── Loader │ │ ├── index.js │ │ └── styles.js │ │ ├── Row.js │ │ └── index.js │ ├── constants │ ├── formats.js │ └── options.js │ ├── containers │ ├── App │ │ └── index.js │ ├── DataMapper │ │ └── index.js │ ├── ExportPage │ │ └── index.js │ ├── ImportPage │ │ └── index.js │ └── Initializer │ │ └── index.js │ ├── hooks │ └── useContentTypes.js │ ├── index.js │ ├── lifecycles.js │ ├── pluginId.js │ ├── translations │ ├── ar.json │ ├── cs.json │ ├── de.json │ ├── en.json │ ├── es.json │ ├── fr.json │ ├── id.json │ ├── index.js │ ├── it.json │ ├── ko.json │ ├── ms.json │ ├── nl.json │ ├── pl.json │ ├── pt-BR.json │ ├── pt.json │ ├── ru.json │ ├── sk.json │ ├── th.json │ ├── tr.json │ ├── uk.json │ ├── vi.json │ ├── zh-Hans.json │ └── zh.json │ └── utils │ ├── exportUtils.js │ ├── formatFileContent.js │ ├── getTrad.js │ ├── highlight.js │ ├── mediaFormat.js │ └── readFileContent.js ├── config └── routes.json ├── constants ├── contentTypes.js ├── permissions.js └── relations.js ├── controllers └── import-export-content.js ├── package.json └── services ├── analyzer.js ├── contentParser ├── csvParser.js ├── index.js └── textFormats.js ├── exporter ├── exportUtils.js └── index.js ├── import-export-content.js ├── importer ├── importMediaFiles.js ├── importUtils.js └── index.js └── utils ├── contentChecker.js ├── fieldUtils.js └── formatsValidator.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = false 6 | indent_style = space 7 | indent_size = 2 8 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # From https://github.com/Danimoth/gitattributes/blob/master/Web.gitattributes 2 | 3 | # Handle line endings automatically for files detected as text 4 | # and leave all files detected as binary untouched. 5 | * text=auto 6 | 7 | # 8 | # The above will handle all files NOT found below 9 | # 10 | 11 | # 12 | ## These files are text and should be normalized (Convert crlf => lf) 13 | # 14 | 15 | # source code 16 | *.php text 17 | *.css text 18 | *.sass text 19 | *.scss text 20 | *.less text 21 | *.styl text 22 | *.js text eol=lf 23 | *.coffee text 24 | *.json text 25 | *.htm text 26 | *.html text 27 | *.xml text 28 | *.svg text 29 | *.txt text 30 | *.ini text 31 | *.inc text 32 | *.pl text 33 | *.rb text 34 | *.py text 35 | *.scm text 36 | *.sql text 37 | *.sh text 38 | *.bat text 39 | 40 | # templates 41 | *.ejs text 42 | *.hbt text 43 | *.jade text 44 | *.haml text 45 | *.hbs text 46 | *.dot text 47 | *.tmpl text 48 | *.phtml text 49 | 50 | # git config 51 | .gitattributes text 52 | .gitignore text 53 | .gitconfig text 54 | 55 | # code analysis config 56 | .jshintrc text 57 | .jscsrc text 58 | .jshintignore text 59 | .csslintrc text 60 | 61 | # misc config 62 | *.yaml text 63 | *.yml text 64 | .editorconfig text 65 | 66 | # build config 67 | *.npmignore text 68 | *.bowerrc text 69 | 70 | # Heroku 71 | Procfile text 72 | .slugignore text 73 | 74 | # Documentation 75 | *.md text 76 | LICENSE text 77 | AUTHORS text 78 | 79 | 80 | # 81 | ## These files are binary and should be left untouched 82 | # 83 | 84 | # (binary is a macro for -text -diff) 85 | *.png binary 86 | *.jpg binary 87 | *.jpeg binary 88 | *.gif binary 89 | *.ico binary 90 | *.mov binary 91 | *.mp4 binary 92 | *.mp3 binary 93 | *.flv binary 94 | *.fla binary 95 | *.swf binary 96 | *.gz binary 97 | *.zip binary 98 | *.7z binary 99 | *.ttf binary 100 | *.eot binary 101 | *.woff binary 102 | *.pyc binary 103 | *.pdf binary 104 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Don't check auto-generated stuff into git 2 | coverage 3 | node_modules 4 | stats.json 5 | package-lock.json 6 | 7 | # Cruft 8 | .DS_Store 9 | npm-debug.log 10 | .idea 11 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Edison Peñuela 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Strapi plugin import-export-content 2 | 3 | Plugin to import and export content according to user permissions in json or csv format. 4 | 5 | ## Installation 6 | 7 | ```bash 8 | yarn add strapi-plugin-import-export-content 9 | ``` 10 | 11 | or 12 | 13 | ```bash 14 | npm i strapi-plugin-import-export-content 15 | ``` 16 | 17 | ## Rebuild your administration panel 18 | 19 | New releases can introduce changes to the administration panel that require a rebuild. Rebuild the admin panel with one of the following commands: 20 | 21 | ```bash 22 | yarn build --clean 23 | ``` 24 | 25 | or 26 | 27 | ```bash 28 | npm run build -- --clean 29 | ``` 30 | 31 | ## Features 32 | 33 | ### Import 34 | 35 | - Read data from CSV and JSON file or from typing raw text 36 | - Import contents to collection or single Type 37 | - Manual mapping from source fields to destination fields 38 | - Recognize format of inputs and content types 39 | - Import content as draft or public 40 | - Upload media from URL 41 | - Import Media by id or object with id key 42 | - Import Relations by id or object with id key 43 | - Import Components and Dynamic Zone Content as json objects 44 | 45 | ### Export 46 | 47 | - Export CSV and JSON contents allowed for the user 48 | - Download files or copy exported data to clipboard 49 | - Options to remove ids and timestamps 50 | - Options to export media as ids, urls, full content or full content without formats 51 | - Options to export relatons as ids or full content 52 | 53 | ## Author 54 | 55 | Edison Peñuela – [@EdisonPeM](https://github.com/EdisonPeM/) – edisonpe961206@hotmail.com 56 | 57 | ## Acknowledgments 58 | 59 | This plugin has been inspired by the tutorial [How to create an import content plugin](https://strapi.io/blog/how-to-create-an-import-content-plugin-part-1-4) 60 | -------------------------------------------------------------------------------- /admin/src/assets/prismjs.css: -------------------------------------------------------------------------------- 1 | /* PrismJS 1.23.0 2 | https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+css+clike+javascript */ 3 | /** 4 | * prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML 5 | * Based on https://github.com/chriskempson/tomorrow-theme 6 | * @author Rose Pritchard 7 | */ 8 | 9 | code[class*="language-"], 10 | pre[class*="language-"] { 11 | color: #ccc; 12 | background: none; 13 | font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; 14 | font-size: 1em; 15 | text-align: left; 16 | white-space: pre; 17 | word-spacing: normal; 18 | word-break: normal; 19 | word-wrap: normal; 20 | line-height: 1.5; 21 | 22 | -moz-tab-size: 4; 23 | -o-tab-size: 4; 24 | tab-size: 4; 25 | 26 | -webkit-hyphens: none; 27 | -moz-hyphens: none; 28 | -ms-hyphens: none; 29 | hyphens: none; 30 | } 31 | 32 | /* Code blocks */ 33 | pre[class*="language-"] { 34 | padding: 1em; 35 | margin: 0.5em 0; 36 | overflow: auto; 37 | } 38 | 39 | :not(pre) > code[class*="language-"], 40 | pre[class*="language-"] { 41 | background: #2d2d2d; 42 | } 43 | 44 | /* Inline code */ 45 | :not(pre) > code[class*="language-"] { 46 | padding: 0.1em; 47 | border-radius: 0.3em; 48 | white-space: normal; 49 | } 50 | 51 | .token.comment, 52 | .token.block-comment, 53 | .token.prolog, 54 | .token.doctype, 55 | .token.cdata { 56 | color: #999; 57 | } 58 | 59 | .token.punctuation { 60 | color: #ccc; 61 | } 62 | 63 | .token.tag, 64 | .token.attr-name, 65 | .token.namespace, 66 | .token.deleted { 67 | color: #e2777a; 68 | } 69 | 70 | .token.function-name { 71 | color: #6196cc; 72 | } 73 | 74 | .token.boolean, 75 | .token.number, 76 | .token.function { 77 | color: #f08d49; 78 | } 79 | 80 | .token.property, 81 | .token.class-name, 82 | .token.constant, 83 | .token.symbol { 84 | color: #f8c555; 85 | } 86 | 87 | .token.selector, 88 | .token.important, 89 | .token.atrule, 90 | .token.keyword, 91 | .token.builtin { 92 | color: #cc99cd; 93 | } 94 | 95 | .token.string, 96 | .token.char, 97 | .token.attr-value, 98 | .token.regex, 99 | .token.variable { 100 | color: #7ec699; 101 | } 102 | 103 | .token.operator, 104 | .token.entity, 105 | .token.url { 106 | color: #67cdcc; 107 | } 108 | 109 | .token.important, 110 | .token.bold { 111 | font-weight: bold; 112 | } 113 | .token.italic { 114 | font-style: italic; 115 | } 116 | 117 | .token.entity { 118 | cursor: help; 119 | } 120 | 121 | .token.inserted { 122 | color: green; 123 | } 124 | -------------------------------------------------------------------------------- /admin/src/components/DataViewer/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import PropTypes from "prop-types"; 3 | import { Code } from "./styles"; 4 | 5 | import formatFileContent from "../../utils/formatFileContent"; 6 | import highlight from "../../utils/highlight"; 7 | 8 | function DataViewer({ data, type }) { 9 | const content = formatFileContent({ 10 | content: data, 11 | mimeType: type, 12 | }); 13 | 14 | const __html = highlight(content, type); 15 | return ( 16 | 17 |
18 | 19 | ); 20 | } 21 | 22 | DataViewer.defaultProps = { 23 | data: "", 24 | type: "", 25 | }; 26 | 27 | DataViewer.propTypes = { 28 | data: PropTypes.string, 29 | type: PropTypes.string, 30 | }; 31 | 32 | export default DataViewer; 33 | -------------------------------------------------------------------------------- /admin/src/components/DataViewer/styles.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | export const Code = styled.pre` 4 | min-height: 200px; 5 | height: 200px; 6 | width: 100%; 7 | border-radius: 4px; 8 | 9 | background: #1e1e1e; 10 | color: #fafafa; 11 | 12 | margin: 0; 13 | padding: 1.2rem; 14 | overflow: auto; 15 | white-space: pre-wrap; 16 | line-height: 2rem; 17 | cursor: auto; 18 | 19 | resize: vertical; 20 | 21 | &::first-line { 22 | color: #f8c555; 23 | } 24 | `; 25 | -------------------------------------------------------------------------------- /admin/src/components/DropFileZone/DragAndDropIcon.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | const DragAndDropIcon = () => ( 4 | 11 | 12 | 18 | 22 | 26 | 30 | 34 | 38 | 42 | 46 | 50 | 54 | 58 | 59 | 60 | 66 | 70 | 74 | 78 | 82 | 86 | 90 | 91 | 92 | 93 | 99 | 100 | 101 | 107 | 108 | 109 | 110 | ); 111 | 112 | export default DragAndDropIcon; 113 | -------------------------------------------------------------------------------- /admin/src/components/DropFileZone/index.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import PropTypes from "prop-types"; 3 | 4 | import DragAndDropIcon from "./DragAndDropIcon"; 5 | import { Label, P } from "./styles"; 6 | 7 | function DropFileZone({ 8 | acceptMimeTypes, 9 | acceptFilesTypes, 10 | onUploadFile, 11 | onUploadError, 12 | }) { 13 | const validateFile = (file) => { 14 | if (acceptMimeTypes.includes(file.type)) { 15 | onUploadFile(file); 16 | } else { 17 | onUploadError(); 18 | } 19 | }; 20 | 21 | const handleFileChange = ({ target: { files } }) => validateFile(files[0]); 22 | 23 | const [isDragging, setIsDragging] = useState(false); 24 | const handleDragEnter = () => setIsDragging(true); 25 | const handleDragLeave = () => setIsDragging(false); 26 | const stopDragEvent = (ev) => ev.preventDefault() && ev.stopPropagation(); 27 | const handleDrop = (ev) => { 28 | ev.preventDefault(); 29 | setIsDragging(false); 30 | 31 | const { files } = ev.dataTransfer; 32 | validateFile(files[0]); 33 | }; 34 | 35 | return ( 36 |