commit f8c170b29a20ed8424e615fb1a4c3724f8c66296 Author: Mysaa Date: Mon May 24 00:22:19 2021 +0200 Premier commit - Inclusion dans le projet git diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..45bbac8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.classpath +.project +.settings/ +bin/ +discordout.ods +testout.ods +testoutout.ods diff --git a/src/com/bernard/math/GraphFunctions.java b/src/com/bernard/math/GraphFunctions.java new file mode 100644 index 0000000..b6ac8db --- /dev/null +++ b/src/com/bernard/math/GraphFunctions.java @@ -0,0 +1,44 @@ +package com.bernard.math; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + +import com.bernard.math.graph.GraphCycleException; + +public class GraphFunctions { + + public static boolean anyCycle(Map> heritages,Function fonction) { + Set patouché = new HashSet(heritages.keySet()); + Set traitage = new HashSet<>(); + try { + while(!patouché.isEmpty()) { + S el = patouché.stream().findAny().get(); + traitation(el,patouché,traitage,heritages,fonction); + } + }catch (GraphCycleException ex) { + return true; + } + return false; + } + + private static void traitation(S s, Set patouché, Set traitage, Map> heritages,Function fonction) throws GraphCycleException{ + patouché.remove(s); + if(!heritages.containsKey(s)) + return; + traitage.add(s); + for(T heritation : heritages.get(s)) { + S enfant = fonction.apply(heritation); + if(patouché.contains(enfant)) + traitation(enfant,patouché,traitage,heritages,fonction); + if(traitage.contains(enfant)) + throw new GraphCycleException(); + // Sinon, ça ne peut pas faire de cycle: parfait ! + } + traitage.remove(s); + return; + } + +} diff --git a/src/com/bernard/math/SortFunctions.java b/src/com/bernard/math/SortFunctions.java new file mode 100644 index 0000000..c988b5f --- /dev/null +++ b/src/com/bernard/math/SortFunctions.java @@ -0,0 +1,59 @@ +package com.bernard.math; + +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +public class SortFunctions { + + public static int compare(Set s1,Set s2,Comparator cprt){ + + // Premier ordre: inclusion + if(s1.containsAll(s2)) + return 1; + if(s2.containsAll(s1)) + return -1; + + //TODO: Refaire cette fonction un peu plus proprement … + + // Second ordre: Majoration de chaque terme + List lt1 = s1.stream().sorted(cprt).collect(Collectors.toList()); + List lt2 = s2.stream().sorted(cprt).collect(Collectors.toList()); + + // Si lt1 < lt2 ? + int i=0,j=0; + while(i0) + break; + } + if(i0) + break; + } + if(i { + + public boolean can(Perm p, Permholder ph); + +} diff --git a/src/com/bernard/permissions/StringPermission.java b/src/com/bernard/permissions/StringPermission.java new file mode 100644 index 0000000..56595b7 --- /dev/null +++ b/src/com/bernard/permissions/StringPermission.java @@ -0,0 +1,247 @@ +package com.bernard.permissions; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import com.bernard.math.SortFunctions; + +public class StringPermission implements Comparable{ + + private Nomme[] nommes; + + public StringPermission(Nomme[] nommes) { + this.nommes = nommes; + } + + public static boolean implies(StringPermission s1,StringPermission s2) { + + if(s2==null)return true; + if(s1==null)return false; + if(s2.nommes.length < s1.nommes.length)return false; + + //Bon déjà, ils ont le même nom + + for (int i = 0; i < s1.nommes.length; i++) + if(Nomme.implies(s1.nommes[i], s2.nommes[i])) + return false; + return true; + } + + public boolean implies(StringPermission other) { + return implies(this,other); + } + + + + //Définition des regex, avec des variables les unes dans les autres. Sinon c'est pas possible + public static final String strR = "(([^\"\\\\]|\\\\\\\\|\\\\\")*)\""; // Without first slash + public static final String optionR = "((\""+strR+"|[^=]+)=(\""+strR+"|[^,\\]]+))"; + public static final String optionsR = "((("+optionR+",)*)"+optionR+")"; + public static final String nnameR = "([^.\"\\[]+)"; + public static final String fullNR = "("+nnameR+"(\\["+optionsR+"\\])?)"; + public static final String spR = "(("+fullNR+"\\.)*)("+fullNR+")"; + + public static final Pattern spregex = Pattern.compile(spR); + public static final Pattern optsregex = Pattern.compile(optionsR); + + public static StringPermission parse(String str) { + + Nomme[] nommes = recParse(str, 0); + + return new StringPermission(nommes); + } + + private static Nomme[] recParse(String str,int index) { + + Matcher mtch = spregex.matcher(str); + if(!mtch.matches()) + throw new IllegalArgumentException(); + + String optionstr = mtch.group(27); + + String nom = mtch.group(25); + + Map options = null; + if(optionstr!=null && !optionstr.isEmpty()) { + options = new HashMap<>(); + String roptions = optionstr; + Matcher optMtch; + do { + optMtch = optsregex.matcher(roptions); + optMtch.matches(); + String name = pppstring(optMtch.group(12),optMtch.group(13)); + String value = pppstring(optMtch.group(15),optMtch.group(16)); + options.put(name, value); + roptions = optMtch.group(2); + roptions = roptions.substring(0, Math.max(roptions.length()-1,0)); + }while(!roptions.isEmpty()); + } + + Nomme nomme = new Nomme(nom, options); + String reste = mtch.group(1); + Nomme[] nommes; + if(reste.isEmpty()) { //Non null car l'étoile de Kleene match le groupe vide + //Dernier parse + nommes = new Nomme[index+1]; + nommes[0] = nomme; + }else { + nommes = recParse(reste.substring(0, reste.length()-1),index+1); // Pof + nommes[nommes.length-1-index] = nomme; + } + return nommes; + } + + public static final String pppstring(String raw,String quoted) { + if(quoted!=null) { + return quoted.replaceAll("\\\\\\\\", "\\").replaceAll("\\\\\"", "\""); + }else { + return raw; + } + } + + public static final String escapeIfNecessary(String raw) { + return escapeIfNecessary(raw, true); + } + public static final String escapeIfNecessary(String raw,boolean canEqualSign) { + if(raw.contains("\"") || raw.contains("\\") || (!canEqualSign && raw.contains("="))) + return "\"" + raw.replaceAll("\\\\", "\\\\").replaceAll("\"", "\\\"") + "\""; + else + return raw; + } + + @Override + public int compareTo(StringPermission sp) { + return this.toString().compareTo(sp.toString()); + } + + @Deprecated //TODO Fix this method with a real order (this one doesn't support nomme's options order) + public int compareTo(StringPermission sp,boolean disabled) { + int l1=this.nommes.length,l2=sp.nommes.length; + for (int k = 0; k < Math.min(l1, l2); k++) { + if(this.nommes[k]!=sp.nommes[k]) + return - this.nommes[k].compareTo(sp.nommes[k]);//TODO: Fix why is this minus sign here + } + //Ici, tous les points sont égaux. Donc on trie du plus court au plus long. + return Integer.compare(l1, l2); + } + + + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Arrays.hashCode(nommes); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + StringPermission other = (StringPermission) obj; + if (!Arrays.equals(nommes, other.nommes)) + return false; + return true; + } + + @Override + public String toString() { + return Arrays.stream(nommes).map(Nomme::toString).collect(Collectors.joining(".")); + } + + + public static class Nomme implements Comparable{ + String name; + Map options; + + public Nomme(String name, Map options) { + this.name = name; + this.options = options; + } + + @Override + public String toString() { + return name + ((options!=null)?("[" + options.entrySet().stream() + .map(e->escapeIfNecessary(e.getKey(),false)+"="+escapeIfNecessary(e.getKey())) + .collect(Collectors.joining(",")) + "]"):""); + } + + public static boolean implies(Nomme n1,Nomme n2) { + if(n2==null)return true; + if(n1==null)return false; + if(n2.name.equals(n1.name))return false; + + //Bon déjà, ils ont le même nom + if(n1.options == null)return true; + if(n2.options == null)return false; //car il ne peut y avoir d'options à n1. + if(!n2.options.keySet().containsAll(n1.options.keySet()))return false; + + // Donc Keys(n1) ⊂ Keys(n2) + // Il ne reste qu'à tester tous les nommes , si leur valeur est égale (ou absente -> Impossible car inclusion) + return n1.options.keySet().stream().allMatch(opt -> n1.options.get(opt).equals(n2.options.get(opt))); + } + + public boolean implies(Nomme other) { + return implies(this,other); + } + + @Override + public int compareTo(Nomme n) { + if(!this.name.equals(n.name)) + return this.name.compareTo(n.name); + if(options==null || n.options==null) + return (options==null)?((n.options==null)?0:-1):1; + System.out.println("bitenbois"); + //On ordonne les options + return SortFunctions.compare(options.entrySet(), + n.options.entrySet(), + (e1,e2) -> (e1.getKey()==e2.getKey()) + ?e1.getValue().compareTo(e2.getValue()) + :e1.getKey().compareTo(e2.getKey())); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((options == null) ? 0 : options.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Nomme other = (Nomme) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (options == null) { + if (other.options != null) + return false; + } else if (!options.equals(other.options)) + return false; + return true; + } + + } + + + +} diff --git a/src/com/bernard/permissions/TestMain.java b/src/com/bernard/permissions/TestMain.java new file mode 100644 index 0000000..3c79b47 --- /dev/null +++ b/src/com/bernard/permissions/TestMain.java @@ -0,0 +1,126 @@ +package com.bernard.permissions; + +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.security.auth.login.LoginException; + +import com.bernard.permissions.tableured.FileManager; +import com.bernard.permissions.tableured.TPermissionContext; +import com.bernard.permissions.tableured.TPermissionContext.Inheritance; +import com.bernard.permissions.tableured.TPermissionContext.Val; +import com.sun.star.uno.Exception; + +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.JDABuilder; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.requests.GatewayIntent; + +public class TestMain { + + public static void main(String[] args) throws Exception, LoginException, InterruptedException{ + + testDiscordRead(); + + System.out.println("OK, i'm done !"); + System.exit(0);; + } + + public static void testReadAndWrite() { + try { + TPermissionContext tpc = FileManager.readFromFile(new File("test.ods")); + String[] perms = {"julia","julia.bdd","julia.bdd.read","julia.bdd.write","julia.messages","julia.coucou"}; + String[] holders = {"Admin","Developeur","Client","Étranger","Mysaa","Bernard","Zlopeg","Ferbex","Pbalkany"}; + for (String perm : perms) { + for (String holder : holders) { + System.out.println(holder+" can "+perm+" : "+tpc.can(StringPermission.parse(perm), holder)); + } + System.out.println("========================="); + } + System.out.println(tpc); + System.out.println("Writing back to file."); + + new File("testout.ods").delete(); + FileManager.writeToFile(new File("testout.ods"), tpc); + System.out.println("Re-reading it"); + TPermissionContext newTPC = FileManager.readFromFile(new File("testout.ods")); + System.out.println(tpc); + System.out.println("Equals test: "+tpc.equals(newTPC)); + System.out.println("Writing to another file"); + FileManager.writeToFile(new File("testoutout.ods"), newTPC); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void testStringPermissions() { + System.out.println(StringPermission.spR); + System.out.println(StringPermission.optionsR); + + String testParse = "pouf[Text=coucou].wow[Quoi=\"Hmm\",bou=2].incroyable.ducul[coucou=genial,super=cool]"; + System.out.println(StringPermission.parse(testParse)); + + } + + public static void testDiscordRead() throws LoginException, InterruptedException, Exception { + JDA jda = JDABuilder.createDefault("",GatewayIntent.GUILD_MEMBERS,GatewayIntent.values()).build(); + jda.awaitReady(); + + Guild g = jda.getGuildById(222947179017404416L); + + Map> specs = new HashMap<>(); + + List roles = g.getRoles(); + + List membres = g.loadMembers().get(); + System.out.println("Membres: "+membres); + + Set defaultGiven = g.getPublicRole().getPermissions().stream() + .map(p -> StringPermission.parse(p.getName())). + collect(Collectors.toSet()); + + Map> inheritance = membres.stream().collect(Collectors.toMap( + m -> "M"+m.getUser().getName()+"#"+m.getUser().getDiscriminator(), + m -> m.getRoles().stream().map(r -> new Inheritance("R"+r.getName(), TPermissionContext.InheritancePolicy.ALL)) + .collect(Collectors.toList()))); + +// for (int i = 1; i < roles.size(); i++) { +// inheritance.put("R"+roles.get(i).getName(), List.of(new Inheritance("R"+roles.get(i-1).getName(),TPermissionContext.InheritancePolicy.ALL))); +// } + + for(Role r : roles) { + for(Permission p : r.getPermissions()) { + StringPermission sp = StringPermission.parse(p.getName()); + if(!specs.containsKey(sp)) + specs.put(sp, new HashMap<>()); + specs.get(sp).put("R"+r.getName(), Val.GRANTED); + } + } +// for(Member m : membres) { +// for(Permission p : m.getPermissions()) { +// StringPermission sp = StringPermission.parse(p.getName()); +// if(!specs.containsKey(sp)) +// specs.put(sp, new HashMap<>()); +// specs.get(sp).put("M"+m.getUser().getName()+"#"+m.getUser().getDiscriminator(), Val.GRANTED); +// } +// } + + + TPermissionContext tpc = new TPermissionContext(defaultGiven, specs, inheritance); + + if(tpc.anyCycle()) + throw new IllegalStateException(); + System.out.println(tpc); + + FileManager.writeToFile(new File("discordout.ods"), tpc); + + } + +} diff --git a/src/com/bernard/permissions/tableured/FileManager.java b/src/com/bernard/permissions/tableured/FileManager.java new file mode 100644 index 0000000..0e38021 --- /dev/null +++ b/src/com/bernard/permissions/tableured/FileManager.java @@ -0,0 +1,370 @@ +package com.bernard.permissions.tableured; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.bernard.permissions.StringPermission; +import com.bernard.permissions.tableured.TPermissionContext.Inheritance; +import com.bernard.permissions.tableured.TPermissionContext.InheritancePolicy; +import com.bernard.permissions.tableured.TPermissionContext.Val; +import com.sun.star.beans.PropertyValue; +import com.sun.star.beans.XPropertySet; +import com.sun.star.comp.helper.Bootstrap; +import com.sun.star.comp.helper.BootstrapException; +import com.sun.star.frame.XComponentLoader; +import com.sun.star.frame.XStorable; +import com.sun.star.lang.XMultiComponentFactory; +import com.sun.star.sheet.XConditionalFormat; +import com.sun.star.sheet.XConditionalFormats; +import com.sun.star.sheet.XSheetCellRange; +import com.sun.star.sheet.XSheetCellRangeContainer; +import com.sun.star.sheet.XSheetCellRanges; +import com.sun.star.sheet.XSpreadsheet; +import com.sun.star.sheet.XSpreadsheetDocument; +import com.sun.star.sheet.XSpreadsheets; +import com.sun.star.table.CellRangeAddress; +import com.sun.star.table.XCell; +import com.sun.star.table.XCellRange; +import com.sun.star.table.XColumnRowRange; +import com.sun.star.uno.Exception; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XComponentContext; +import com.sun.star.util.XCloseable; +import com.sun.star.util.XMergeable; + +public class FileManager { + + private static XComponentContext xcc_noaccess; + + public static final int MAX_ROW = 3141; + public static final int MAX_COL = 3141; + + public static XComponentContext xcc() { + if (xcc_noaccess == null) { + try { + xcc_noaccess = Bootstrap.bootstrap(); + System.out.println("Connected to a running office ..."); + } catch (BootstrapException e) { + System.err.println("Couldn't connect to office, you won't be able to use "); + } + } + return xcc_noaccess; + } + + //TODO: remove «throws Exception» for more precise exceptions + + public static final TPermissionContext readFromFile(File f) throws Exception { + + XComponentContext xcc = xcc(); + XMultiComponentFactory xmcf; + XSpreadsheetDocument xsd; + + xmcf = xcc.getServiceManager(); + Object object = xmcf.createInstanceWithContext("com.sun.star.frame.Desktop", xcc); + XComponentLoader xComponentLoader = qi(XComponentLoader.class,object); + PropertyValue[] docLoadProperties = { new PropertyValue() }; + docLoadProperties[0].Name = "Hidden"; + docLoadProperties[0].Value = true; + xsd = qi(XSpreadsheetDocument.class, + xComponentLoader.loadComponentFromURL("file://"+f.getAbsolutePath(), "_blank", 0, docLoadProperties)); + + // Variables de sortie: + Set defaultGiven = new HashSet<>(); + Map> specs = new HashMap<>(); + Map> inheritance = new HashMap<>(); + + + String[] sheetNames = xsd.getSheets().getElementNames(); + for (int s = 0; s < sheetNames.length; s++) { + String sheetName = sheetNames[s]; + XSpreadsheet sheet = qi(XSpreadsheet.class,xsd.getSheets().getByName(sheetName)); + + // Si c'est des permissions + if(sheetName.startsWith("Permission")) { + + // Parsing users/groups names + int defaultColIndex; + List holders = new ArrayList<>(); + // PermName,…,…,…,Default + for(defaultColIndex = 1;!sheet.getCellByPosition(defaultColIndex+1, 0).getFormula().equals("#~END~#") && defaultColIndex thisSpec = new HashMap<>(); + + + + for(int hi=0;hi inhz = null; + + for(int col = 1;!sheet.getCellByPosition(col, 0).getFormula().equals("#~END~#") && col <= MAX_COL;col++) { + String rule = sheet.getCellByPosition(col, i).getFormula(); + if(!rule.isBlank()) { + InheritancePolicy ipol = InheritancePolicy.fromChar(rule.charAt(0)); + String motherHolderName = (ipol==InheritancePolicy.ALL)?rule:rule.substring(1); + + if(inhz==null) + inhz = new ArrayList<>(); + inhz.add(new Inheritance(motherHolderName, ipol)); + } + } + if(inhz!=null) + inheritance.put(holder, inhz); + + + } + + + } + } + + System.out.println(defaultGiven); + System.out.println(specs); + System.out.println(inheritance); + + TPermissionContext tpc = new TPermissionContext(defaultGiven, specs, inheritance); + if(tpc.anyCycle()) + throw new IllegalArgumentException("Cycle detected !"); + + return tpc; + } + + public static final void writeToFile(File f,TPermissionContext tpc) throws Exception { + + XComponentContext xcc = xcc(); + XMultiComponentFactory xmcf; + XSpreadsheetDocument xsd; + + xmcf = xcc.getServiceManager(); + + xmcf = xcc.getServiceManager(); + Object object = xmcf.createInstanceWithContext("com.sun.star.frame.Desktop", xcc); + XComponentLoader xcl = qi(XComponentLoader.class,object); + + PropertyValue[] docLoadProperties = { new PropertyValue() }; + docLoadProperties[0].Name = "Hidden"; + docLoadProperties[0].Value = true; + String baseFile = new File("stringPermissionBase.ods").getAbsolutePath(); + + xsd = UnoRuntime.queryInterface( + XSpreadsheetDocument.class, xcl.loadComponentFromURL("file://"+baseFile, "_blank", 0, docLoadProperties )); + + XSpreadsheets sheets = xsd.getSheets(); + + + XSpreadsheet permissionsS = qi(XSpreadsheet.class,sheets.getByName("Permissions")); + XSpreadsheet permissionsCompleteS = qi(XSpreadsheet.class,sheets.getByName("Permissions-complete")); + XSpreadsheet holdersS = qi(XSpreadsheet.class,sheets.getByName("Holders")); + + + + + // ----- Permissions sheet ----- + + writePermissionsSheetOutline(tpc, permissionsS,false); + + + + + //TODO: Ajouter le support pour les holders qui commencent par un + ou un - (avec ++=+, +++=++, ...) + //TODO: Faire un tri qui «garde la structure du graphe d'héritage» + + // ----- Heritance sheet ----- + List enfants = tpc.inheritance.keySet().stream().sorted().collect(Collectors.toList()); + + holdersS.getCellByPosition(0, 0).setFormula("Holder");; + holdersS.getCellByPosition(1, 0).setFormula("Héritages");; + System.out.println(tpc.inheritance); + int maxCol = 0; + for(int i=0;i parents = tpc.inheritance.get(enfants.get(i)); + for (int j = 0; j < parents.size(); j++) { + String toWrite = parents.get(j).policy.toChar()+parents.get(j).holder; + holdersS.getCellByPosition(j+1, i+1).setFormula(toWrite); + } + maxCol = Math.max(maxCol, parents.size()); + } + + // Adding the style on the heritance core. + XSheetCellRange xscr = qi(XSheetCellRange.class,holdersS.getCellRangeByPosition(1,0,maxCol,0)); + System.out.println(xscr); + qi(XMergeable.class,xscr).merge(true); + for(int i=0;i permissions = Stream.concat( + tpc.specs.keySet().stream(), + tpc.defaultGiven.stream() + ).distinct().sorted().collect(Collectors.toList()); + List permSpecHolders = Stream.concat(tpc.inheritance.keySet().stream(),tpc.specs.values().stream().flatMap(m -> m.keySet().stream())).distinct().sorted().collect(Collectors.toList()); + //TODO: Find a way to distinct and sorted at the same time + for (int i = 0; i < permissions.size(); i++) { + XCell cell = permissionsS.getCellByPosition(0,i+1); + cell.setFormula(permissions.get(i).toString()); + qi(XPropertySet.class, cell).setPropertyValue("CellStyle", (i%2==0)?"SpecPermissionEven":"SpecPermissionOdd"); + } + for (int j = 0; j < permSpecHolders.size(); j++) { + XCell cell = permissionsS.getCellByPosition(j+1,0); + cell.setFormula(permSpecHolders.get(j)); + qi(XPropertySet.class, cell).setPropertyValue("CellStyle", (j%2==0)?"SpecHolderEven":"SpecHolderOdd"); + } + + int defaultHolderCol = permSpecHolders.size()+1; + XCell celld = permissionsS.getCellByPosition(defaultHolderCol,0); + celld.setFormula("#~DEFAULT~#"); + qi(XPropertySet.class, celld).setPropertyValue("CellStyle", "SpecHolderDefault"); + + for(Entry> etry : tpc.specs.entrySet()) { + int permIndex = Collections.binarySearch(permissions, etry.getKey()); + for(Entry ett : etry.getValue().entrySet()) { + int hldrIndex = Collections.binarySearch(permSpecHolders, ett.getKey()); + if(ett.getValue()!=Val.UNSPECIFIED) + permissionsS.getCellByPosition(hldrIndex+1,permIndex+1).setFormula(String.valueOf(ett.getValue().toChar())); + } + } + // Writing the DEFAULT column + for(int i = 0;i dg.implies(sp))) + permissionsS.getCellByPosition(defaultHolderCol, i+1).setFormula("."); + else + permissionsS.getCellByPosition(defaultHolderCol, i+1).setFormula("_"); + } + if(writeEverything) { + for(int j = 0;j T qi(Class aType, Object o) { + return UnoRuntime.queryInterface(aType, o); + } + +} diff --git a/src/com/bernard/permissions/tableured/TPermissionContext.java b/src/com/bernard/permissions/tableured/TPermissionContext.java new file mode 100644 index 0000000..92e8002 --- /dev/null +++ b/src/com/bernard/permissions/tableured/TPermissionContext.java @@ -0,0 +1,226 @@ +package com.bernard.permissions.tableured; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.bernard.math.GraphFunctions; +import com.bernard.permissions.PermissionContext; +import com.bernard.permissions.StringPermission; + +public class TPermissionContext implements PermissionContext { + + Set defaultGiven; + + //List permHolder; + //List permissions; + //Val[][] specs; + + Map> specs; // > + + Map> inheritance; // Par ordre chronologique + // Si [0] revoke et [1] grant, alors sera granted + + + + + public TPermissionContext(Set defaultGiven, Map> specs, Map> inheritance) { + this.defaultGiven = defaultGiven; + this.specs = specs; + this.inheritance = inheritance; + } + + @Override + public boolean can(StringPermission p, String ph) { + Val value = isRightGiven(p, ph); + if(value==Val.UNSPECIFIED) { + for(StringPermission perm : defaultGiven) { + if(perm.implies(p)) + return true; + } + return false; + } + return value==Val.GRANTED; + } + + public Val isRightGiven(StringPermission p, String ph) { + + for(StringPermission perm : specs.keySet()) { + if(perm.implies(p) && specs.get(perm).get(ph)==Val.GRANTED) + return Val.GRANTED; + if(p.implies(perm) && specs.get(perm).get(ph)==Val.REVOKED) + return Val.REVOKED; + } + + if(!inheritance.containsKey(ph)) + return Val.UNSPECIFIED; + + // Here, the permission is neither specifically given or revoked to this user. + // Let's check the parents. + List inhz = inheritance.get(ph); + + //Ordonné, car les premiers héritages sont prioritaires. + for(Inheritance ancetre: inhz) { + Val value = isRightGiven(p, ancetre.holder); + if(value == Val.UNSPECIFIED) + continue; // Cet ancetre n'a pas de spécification pour cette permission, on passe. + if(ancetre.policy==InheritancePolicy.ALL + || (ancetre.policy==InheritancePolicy.GRANT_ALL && value==Val.GRANTED) + || (ancetre.policy==InheritancePolicy.REVOKE_ALL && value==Val.REVOKED)) + return value; // != UNSPECIFIED + //Sinon, on ne sait pas. + } + + return Val.UNSPECIFIED; + } + + + public boolean anyCycle() { + return GraphFunctions.anyCycle(inheritance, i -> i.holder); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((defaultGiven == null) ? 0 : defaultGiven.hashCode()); + result = prime * result + ((inheritance == null) ? 0 : inheritance.hashCode()); + result = prime * result + ((specs == null) ? 0 : specs.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj)//FIXME: This doesnt work ... + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TPermissionContext other = (TPermissionContext) obj; + if (defaultGiven == null) { + if (other.defaultGiven != null) + return false; + } else if (!defaultGiven.equals(other.defaultGiven)) + return false; + if (inheritance == null) { + if (other.inheritance != null) + return false; + } else if (!inheritance.equals(other.inheritance)) + return false; + if (specs == null) { + if (other.specs != null) + return false; + } else if (!specs.equals(other.specs)) + return false; + return true; + } + + @Override + public String toString() { + return "TPermissionContext [defaultGiven=" + defaultGiven + ", specs=" + specs + ", inheritance=" + inheritance + + "]"; + } + + + + + + + public static enum Val { + UNSPECIFIED, + GRANTED, + REVOKED; + + public char toChar() { + switch(this) { + case GRANTED: + return 'o'; + case REVOKED: + return 'x'; + case UNSPECIFIED: + } + return (char)0x0; + } + } + + public static class Inheritance{ + String holder; + InheritancePolicy policy; + + + + public Inheritance(String holder, InheritancePolicy policy) { + this.holder = holder; + this.policy = policy; + } + + public String getHolder() { + return holder; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((holder == null) ? 0 : holder.hashCode()); + result = prime * result + ((policy == null) ? 0 : policy.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Inheritance other = (Inheritance) obj; + if (holder == null) { + if (other.holder != null) + return false; + } else if (!holder.equals(other.holder)) + return false; + if (policy != other.policy) + return false; + return true; + } + + @Override + public String toString() { + return "Inheritance [holder=" + holder + ", policy=" + policy + "]"; + } + + + + } + + public static enum InheritancePolicy{ + GRANT_ALL, + REVOKE_ALL, + ALL; + + public static InheritancePolicy fromChar(char chr) { + switch(chr) { + case '+': + return GRANT_ALL; + case '-': + return REVOKE_ALL; + default: + return ALL; + } + } + public char toChar() { + switch(this) { + case GRANT_ALL: + return '+'; + case REVOKE_ALL: + return '-'; + default: + return (char)0x0; + } + } + } + +} diff --git a/stringPermissionBase.ods b/stringPermissionBase.ods new file mode 100644 index 0000000..6e39b38 Binary files /dev/null and b/stringPermissionBase.ods differ diff --git a/test.ods b/test.ods new file mode 100644 index 0000000..7ce99d1 Binary files /dev/null and b/test.ods differ