/** * Axelor Business Solutions * * Copyright (C) 2016 Axelor (<http://axelor.com>). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.axelor.auth.service; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; import org.apache.commons.io.output.FileWriterWithEncoding; import org.joda.time.LocalDateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import au.com.bytecode.opencsv.CSVReader; import au.com.bytecode.opencsv.CSVWriter; import com.axelor.app.AppSettings; import com.axelor.auth.db.Group; import com.axelor.auth.db.IMessage; import com.axelor.auth.db.Permission; import com.axelor.auth.db.PermissionAssistant; import com.axelor.auth.db.repo.GroupRepository; import com.axelor.auth.db.repo.PermissionAssistantRepository; import com.axelor.auth.db.repo.PermissionRepository; import com.axelor.i18n.I18n; import com.axelor.inject.Beans; import com.axelor.meta.MetaFiles; import com.axelor.meta.db.MetaField; import com.axelor.meta.db.MetaFile; import com.axelor.meta.db.MetaModel; import com.axelor.meta.db.MetaPermission; import com.axelor.meta.db.MetaPermissionRule; import com.axelor.meta.db.repo.MetaModelRepository; import com.axelor.meta.db.repo.MetaPermissionRepository; import com.axelor.meta.db.repo.MetaPermissionRuleRepository; import com.google.common.base.Strings; import com.google.inject.Inject; import com.google.inject.persist.Transactional; public class PermissionAssistantService { private static final Logger LOG = LoggerFactory.getLogger(PermissionAssistantService.class); @Inject private MetaPermissionRepository metaPermissionRepository; @Inject private PermissionRepository permissionRepository; @Inject private MetaPermissionRuleRepository ruleRepository; @Inject private GroupRepository groupRepository; @Inject private MetaModelRepository modelRepository; private String errorLog = ""; @SuppressWarnings("serial") private List<String> groupHeader = new ArrayList<String>(){{ add(""); add(I18n.get("Read")); add(I18n.get("Write")); add(I18n.get("Create")); add(I18n.get("Delete")); add(I18n.get("Export")); add(I18n.get("Readonly If")); add(I18n.get("Hide If")); }}; private String getFileName(PermissionAssistant assistant){ String userCode = assistant.getCreatedBy().getCode(); String dateString = LocalDateTime.now().toString("yyyyMMddHHmm"); String fileName = userCode + "-" + dateString + ".csv"; return fileName; } public void createFile(PermissionAssistant assistant){ AppSettings appSettings = AppSettings.get(); File permFile = new File(appSettings.get("file.upload.dir"), getFileName(assistant)); try { FileWriterWithEncoding fileWriter = new FileWriterWithEncoding(permFile, "utf-8"); CSVWriter csvWriter = new CSVWriter(fileWriter, ';'); writeGroup(csvWriter, assistant); csvWriter.close(); createMetaFile(permFile, assistant); } catch (Exception e) { e.printStackTrace(); } } @Transactional public void createMetaFile(File permFile, PermissionAssistant assistant) { MetaFile metaFile = new MetaFile(); metaFile.setFileName(permFile.getName()); metaFile.setFilePath(permFile.getName()); assistant.setMetaFile(metaFile); Beans.get(PermissionAssistantRepository.class).save(assistant); } private void writeGroup(CSVWriter csvWriter, PermissionAssistant assistant) { @SuppressWarnings("serial") List<String> headerRow = new ArrayList<String>(){{ add("Object"); add("Field"); add("Title"); }}; String[] groupRow = new String[assistant.getGroupSet().size()*8+3]; Integer count = 3; for(Group group : assistant.getGroupSet()){ groupRow[count+1] = group.getCode(); headerRow.addAll(groupHeader); count += 8; } LOG.debug("Header row created: {}",headerRow); csvWriter.writeNext(groupRow); csvWriter.writeNext(headerRow.toArray(groupRow)); writeObject(csvWriter, assistant, groupRow.length); } public Comparator<Object> compareField() { return new Comparator<Object>() { @Override public int compare(Object field1, Object field2) { return ((MetaField)field1).getName().compareTo(((MetaField)field2).getName()); } }; } private void writeObject(CSVWriter csvWriter, PermissionAssistant assistant, Integer size) { String language = assistant.getLanguage(); language = language != null ? language : "en"; LOG.debug("Language selected: {}",language); ResourceBundle bundle = I18n.getBundle(new Locale(language)); for(MetaModel object : assistant.getObjectSet()){ String[] row = new String[size]; row[0] = object.getFullName(); csvWriter.writeNext(row); List<MetaField> fieldList = object.getMetaFields(); Collections.sort(fieldList, compareField()); for(MetaField field : fieldList){ row = new String[size]; row[1] = field.getName(); String title = field.getLabel(); if(!Strings.isNullOrEmpty(title)){ title = bundle.getString(title); } row[2] = title; csvWriter.writeNext(row); } } } private boolean checkHeaderRow(String[] headerRow){ @SuppressWarnings("serial") List<String> headerList = new ArrayList<String>(){{ add("Object"); add("Field"); add("Title"); }}; Integer count = 3; while(count < headerRow.length){ headerList.addAll(groupHeader); count += 8; } LOG.debug("Standard Headers: {}",headerList); String[] headers = headerList.toArray(new String[headerList.size()]); LOG.debug("File Headers: {}",Arrays.asList(headerRow)); return Arrays.equals(headers, headerRow); } public String importPermissions(PermissionAssistant permissionAssistant){ try { MetaFile metaFile = permissionAssistant.getMetaFile(); File csvFile = MetaFiles.getPath(metaFile).toFile(); CSVReader csvReader = new CSVReader(new FileReader(csvFile), ';'); String[] groupRow = csvReader.readNext(); if(groupRow == null || groupRow.length < 11){ errorLog = I18n.get(IMessage.BAD_FILE); } String[] headerRow = csvReader.readNext(); if(headerRow == null){ errorLog = I18n.get(IMessage.NO_HEADER); } if(!checkHeaderRow(headerRow)){ errorLog = I18n.get(IMessage.BAD_HEADER)+Arrays.asList(headerRow); } if(!errorLog.equals("")){ csvReader.close(); return errorLog; } Map<String,Group> groupMap = checkBadGroups(groupRow); Map<String, MetaPermission> metaPermissionDict = new HashMap<String, MetaPermission>(); processCSV(csvReader, groupRow, null, metaPermissionDict, groupMap); saveGroups(groupMap); } catch (Exception e) { e.printStackTrace(); errorLog += "\n"+String.format(I18n.get(IMessage.ERR_IMPORT_WITH_MSG), e.getMessage()); } return errorLog; } @Transactional public void saveGroups(Map<String, Group> groupMap) { for(Group group: groupMap.values()){ groupRepository.save(group); } } private Map<String,Group> checkBadGroups(String[] groupRow){ List<String> badGroups = new ArrayList<String>(); Map<String,Group> groupMap = new HashMap<String, Group>(); for(Integer glen = 4; glen<groupRow.length; glen+=8){ String groupName = groupRow[glen]; Group group = groupRepository.all().filter("self.code = ?1", groupName).fetchOne(); if(group == null){ badGroups.add(groupName); } else{ groupMap.put(groupName, group); } } if(!badGroups.isEmpty()){ errorLog += "\n"+String.format(I18n.get(IMessage.NO_GROUP), badGroups); } return groupMap; } private String checkObject(String objectName){ MetaModel model = modelRepository.all().filter("self.fullName = ?1", objectName).fetchOne(); if(model == null){ errorLog += "\n"+String.format(I18n.get(IMessage.NO_OBJECT), objectName); return null; } return objectName; } private void processCSV(CSVReader csvReader, String[] groupRow, String objectName, Map<String, MetaPermission> metaPermissionDict, Map<String,Group> groupMap) throws IOException{ String[] row = csvReader.readNext(); if(row == null){ return; } for(Integer groupIndex = 4; groupIndex < row.length; groupIndex += 8){ String groupName = groupRow[groupIndex]; if(!groupMap.containsKey(groupName)) {continue;} String[] rowGroup = (String[]) Arrays.copyOfRange(row, groupIndex, groupIndex + 8); if(!Strings.isNullOrEmpty(groupName) && !Strings.isNullOrEmpty(row[0])){ objectName = checkObject(row[0]); if(objectName == null){ break; } metaPermissionDict.put(groupName, getMetaPermission(groupMap.get(groupName), objectName)); updatePermission(groupMap.get(groupName), objectName, rowGroup); } else if(objectName != null && !Strings.isNullOrEmpty(row[1])){ updateFieldPermission(metaPermissionDict.get(groupName), row[1], rowGroup); } } processCSV(csvReader, groupRow, objectName, metaPermissionDict, groupMap); } public MetaPermission getMetaPermission(Group group, String objectName){ String[] objectNames = objectName.split("\\."); String groupName = group.getCode(); String permName = groupName + "." + objectNames[objectNames.length - 1]; MetaPermission metaPermission = metaPermissionRepository.all().filter("self.name = ?1", permName).fetchOne(); if(metaPermission == null){ LOG.debug("Create metaPermission group: {}, object: {}", groupName, objectName); metaPermission = new MetaPermission(); metaPermission.setName(permName); metaPermission.setObject(objectName); group.addMetaPermission(metaPermission); } return metaPermission; } public MetaPermission updateFieldPermission(MetaPermission metaPermission, String field, String[] row) { MetaPermissionRule permissionRule = ruleRepository.all().filter("self.field = ?1 and self.metaPermission.name = ?2", field,metaPermission.getName()).fetchOne(); if(permissionRule == null){ permissionRule = new MetaPermissionRule(); permissionRule.setMetaPermission(metaPermission); permissionRule.setField(field); } permissionRule.setCanRead(row[0].equalsIgnoreCase("x")); permissionRule.setCanWrite(row[1].equalsIgnoreCase("x")); permissionRule.setCanExport(row[4].equalsIgnoreCase("x")); permissionRule.setReadonlyIf(row[5]); permissionRule.setHideIf(row[6]); metaPermission.addRule(permissionRule); return metaPermission; } public void updatePermission(Group group, String objectName, String[] row) { String[] objectNames = objectName.split("\\."); String groupName = group.getCode(); String permName = groupName + "." + objectNames[objectNames.length-1]; Permission permission = permissionRepository.all().filter("self.name = ?1", permName).fetchOne(); boolean newPermission = false; if(permission == null){ newPermission = true; permission = new Permission(); permission.setName(permName); permission.setObject(objectName); } permission.setCanRead(row[0].equalsIgnoreCase("x")); permission.setCanWrite(row[1].equalsIgnoreCase("x")); permission.setCanCreate(row[2].equalsIgnoreCase("x")); permission.setCanRemove(row[3].equalsIgnoreCase("x")); permission.setCanExport(row[4].equalsIgnoreCase("x")); if(newPermission){ group.addPermission(permission); } } }