Premier commit - Inclusion dans le projet git

This commit is contained in:
Mysaa 2021-05-24 00:22:19 +02:00
commit f8c170b29a
11 changed files with 1093 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
.classpath
.project
.settings/
bin/
discordout.ods
testout.ods
testoutout.ods

View File

@ -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 <S,T> boolean anyCycle(Map<S,List<T>> heritages,Function<T,S> fonction) {
Set<S> patouché = new HashSet<S>(heritages.keySet());
Set<S> 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 <S,T> void traitation(S s, Set<S> patouché, Set<S> traitage, Map<S,List<T>> heritages,Function<T,S> 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;
}
}

View File

@ -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 <T> int compare(Set<T> s1,Set<T> s2,Comparator<T> 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<T> lt1 = s1.stream().sorted(cprt).collect(Collectors.toList());
List<T> lt2 = s2.stream().sorted(cprt).collect(Collectors.toList());
// Si lt1 < lt2 ?
int i=0,j=0;
while(i<lt1.size() && j<lt2.size()) {
int val = cprt.compare(lt1.get(i), lt2.get(j));
if(val<0)
i++;
else if(val>0)
break;
}
if(i<lt1.size() && j<lt2.size())
return -1;
// Si lt1 < lt2 ?
i=0;
j=0;
while(i<lt1.size() && j<lt2.size()) {
int val = cprt.compare(lt2.get(i), lt1.get(j));
if(val<0)
i++;
else if(val>0)
break;
}
if(i<lt1.size() && j<lt2.size())
return 1;
//Troisième ordre Du coup on revient à un tri lexicographique.
if(lt1.size()!=lt2.size())
return Integer.compare(lt2.size(), lt1.size());
for (int k = 0; k < lt1.size(); k++) {
if(lt1.get(k)!=lt2.get(k))
return cprt.compare(lt1.get(k), lt2.get(k));
}
return 0; //, on a vraiment tous les termes triés égaux, donc. On peut dire qu'il y a égalité ^^
}
}

View File

@ -0,0 +1,7 @@
package com.bernard.math.graph;
public class GraphCycleException extends Exception {
private static final long serialVersionUID = -39387746213824654L;
}

View File

@ -0,0 +1,7 @@
package com.bernard.permissions;
public interface PermissionContext<Perm,Permholder> {
public boolean can(Perm p, Permholder ph);
}

View File

@ -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<StringPermission>{
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<String,String> 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<Nomme>{
String name;
Map<String,String> options;
public Nomme(String name, Map<String, String> 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;
}
}
}

View File

@ -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<StringPermission,Map<String,Val>> specs = new HashMap<>();
List<Role> roles = g.getRoles();
List<Member> membres = g.loadMembers().get();
System.out.println("Membres: "+membres);
Set<StringPermission> defaultGiven = g.getPublicRole().getPermissions().stream()
.map(p -> StringPermission.parse(p.getName())).
collect(Collectors.toSet());
Map<String,List<Inheritance>> 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);
}
}

View File

@ -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<StringPermission> defaultGiven = new HashSet<>();
Map<StringPermission, Map<String, Val>> specs = new HashMap<>();
Map<String, List<Inheritance>> 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<String> holders = new ArrayList<>();
// PermName,,,,Default
for(defaultColIndex = 1;!sheet.getCellByPosition(defaultColIndex+1, 0).getFormula().equals("#~END~#") && defaultColIndex<MAX_COL;defaultColIndex++) {
holders.add(sheet.getCellByPosition(defaultColIndex, 0).getFormula());
}
//Devrait être sur la bonne colonne.
System.out.println(holders);
// Parsing file names
for (int i = 1;!sheet.getCellByPosition(0, i).getFormula().equals("#~END~#") && i<=MAX_ROW; i++) {
String perm = sheet.getCellByPosition(0, i).getFormula();
if(!perm.isBlank()) {
Map<String, Val> thisSpec = new HashMap<>();
for(int hi=0;hi<holders.size();hi++) {
String holder = holders.get(hi);
if(holder==null)continue;
String value = sheet.getCellByPosition(hi+1, i).getFormula();
if(!value.isEmpty()) {
switch(value.charAt(0)) {
case 'x':
case 'X':
thisSpec.put(holder, TPermissionContext.Val.REVOKED);
break;
case 'o':
case 'O':
thisSpec.put(holder, TPermissionContext.Val.GRANTED);
break;
}
}
}
StringPermission perperm = StringPermission.parse(perm);
specs.put(perperm, thisSpec);
//Putting the default
String defaultValue = sheet.getCellByPosition(defaultColIndex, i).getFormula();
if(!defaultValue.isBlank()) {
char defaultValueChar = defaultValue.charAt(0);
if(defaultValueChar=='o' || defaultValueChar=='O')
defaultGiven.add(perperm);
}
}
}
}else if(sheetName.startsWith("Holder")) {
// Parsing file names
for (int i = 1;!sheet.getCellByPosition(0, i).getFormula().equals("#~END~#") && i<=MAX_ROW; i++) {
String holder = sheet.getCellByPosition(0, i).getFormula();
List<Inheritance> 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<String> 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<enfants.size();i++) {
XCell cellEnft = holdersS.getCellByPosition(0,i+1);
cellEnft.setFormula(enfants.get(i));
qi(XPropertySet.class, cellEnft).setPropertyValue("CellStyle", (i%2==0)?"HeritageHolderEven":"HeritageHolderOdd");
List<Inheritance> 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<enfants.size();i++) {
XCellRange cellr = holdersS.getCellRangeByPosition(1,i+1,maxCol,i+1);
qi(XPropertySet.class, cellr).setPropertyValue("CellStyle", (i%2==0)?"HeritageEven":"HeritageOdd");
}
// Adding the #~END~# labels
holdersS.getCellByPosition(maxCol+1, 0).setFormula("#~END~#");;
holdersS.getCellByPosition(0, enfants.size()+1).setFormula("#~END~#");;
XCellRange cellrv = holdersS.getCellRangeByPosition(maxCol+1,0,maxCol+1,enfants.size()+1);
qi(XPropertySet.class, cellrv).setPropertyValue("CellStyle", "EndLine");
XCellRange cellrh = holdersS.getCellRangeByPosition(0,enfants.size()+1,maxCol+1,enfants.size()+1);
qi(XPropertySet.class, cellrh).setPropertyValue("CellStyle", "EndLine");
// Réduis les tailles des dernières colonnes et lignes
XColumnRowRange colignes = qi(XColumnRowRange.class,holdersS);
qi(XPropertySet.class,colignes.getColumns().getByIndex(maxCol+1)).setPropertyValue("Width", 420);;
qi(XPropertySet.class,colignes.getRows().getByIndex(enfants.size()+1)).setPropertyValue("Height", 420);;
// ----- Permissions-Complete sheet -----
// We have two implication graphes: one for holders with inheritance.
writePermissionsSheetOutline(tpc, permissionsCompleteS, true);
// ----- Écrit le fichier -----
String fileURL = "file://"+f.getAbsolutePath();
XStorable xst = qi(XStorable.class, xsd);
PropertyValue[] propertyValue = {new PropertyValue()};
propertyValue[0] = new com.sun.star.beans.PropertyValue();
propertyValue[0].Name = "Overwrite";
propertyValue[0].Value = Boolean.TRUE;
xst.storeAsURL( fileURL, propertyValue );
XCloseable xcloz = qi(XCloseable.class, xsd );
xcloz.close(false);
}
private static void writePermissionsSheetOutline(TPermissionContext tpc, XSpreadsheet permissionsS,boolean writeEverything) throws Exception {
//C'est de base des Sets, mais sont ordonnés, pour un affichage consistant.
List<StringPermission> permissions = Stream.concat(
tpc.specs.keySet().stream(),
tpc.defaultGiven.stream()
).distinct().sorted().collect(Collectors.toList());
List<String> 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<StringPermission,Map<String,Val>> etry : tpc.specs.entrySet()) {
int permIndex = Collections.binarySearch(permissions, etry.getKey());
for(Entry<String,Val> 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<permissions.size();i++) {
StringPermission sp = StringPermission.parse(permissionsS.getCellByPosition(0, i+1).getFormula());
if(tpc.defaultGiven.contains(sp))
permissionsS.getCellByPosition(defaultHolderCol, i+1).setFormula("o");
else if(tpc.defaultGiven.stream().anyMatch(dg -> dg.implies(sp)))
permissionsS.getCellByPosition(defaultHolderCol, i+1).setFormula(".");
else
permissionsS.getCellByPosition(defaultHolderCol, i+1).setFormula("_");
}
if(writeEverything) {
for(int j = 0;j<permSpecHolders.size();j++) {
for(int i = 0;i<permissions.size();i++) {
if(permissionsS.getCellByPosition(j+1,i+1).getFormula().isBlank())
permissionsS.getCellByPosition(j+1,i+1).setFormula(tpc.can(permissions.get(i), permSpecHolders.get(j))?".":"_");
}
}
}
// Adding the #~END~# labels
permissionsS.getCellByPosition(0,permissions.size()+1).setFormula("#~END~#");;
permissionsS.getCellByPosition(defaultHolderCol+1, 0).setFormula("#~END~#");;
XCellRange cellrv = permissionsS.getCellRangeByPosition(defaultHolderCol+1,0,defaultHolderCol+1,permissions.size()+1);
qi(XPropertySet.class, cellrv).setPropertyValue("CellStyle", "EndLine");
XCellRange cellrh = permissionsS.getCellRangeByPosition(0,permissions.size()+1,defaultHolderCol+1,permissions.size()+1);
qi(XPropertySet.class, cellrh).setPropertyValue("CellStyle", "EndLine");
// Réduis les tailles des dernières colonnes et lignes
XColumnRowRange colignes = qi(XColumnRowRange.class,permissionsS);
qi(XPropertySet.class,colignes.getColumns().getByIndex(defaultHolderCol+1)).setPropertyValue("Width", 420);;
qi(XPropertySet.class,colignes.getRows().getByIndex(permissions.size()+1)).setPropertyValue("Height", 420);;
// Applique le formattage conditionel aux données
XConditionalFormats formats = qi(XConditionalFormats.class,qi(XPropertySet.class,permissionsS).getPropertyValue("ConditionalFormats"));
XConditionalFormat theFormat = formats.getConditionalFormats()[0];
XSheetCellRanges applicationRanges = qi(XSheetCellRanges.class,qi(XPropertySet.class,theFormat).getPropertyValue("Range"));
XSheetCellRangeContainer applicationRangesP = qi(XSheetCellRangeContainer.class,applicationRanges);
applicationRangesP.addRangeAddress(new CellRangeAddress((short)0, 1, 1, defaultHolderCol, permissions.size()), true);
qi(XPropertySet.class,theFormat).setPropertyValue("Range", applicationRangesP);
}
public static <T> T qi(Class<T> aType, Object o) {
return UnoRuntime.queryInterface(aType, o);
}
}

View File

@ -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<StringPermission,String> {
Set<StringPermission> defaultGiven;
//List<String> permHolder;
//List<StringPermission> permissions;
//Val[][] specs;
Map<StringPermission,Map<String,Val>> specs; // <permHolder,<permission,value>>
Map<String,List<Inheritance>> inheritance; // Par ordre chronologique
// Si [0] revoke et [1] grant, alors sera granted
public TPermissionContext(Set<StringPermission> defaultGiven, Map<StringPermission, Map<String, Val>> specs, Map<String, List<Inheritance>> 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<Inheritance> 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;
}
}
}
}

BIN
stringPermissionBase.ods Normal file

Binary file not shown.

BIN
test.ods Normal file

Binary file not shown.